Perl: Bytes einer Binär-Datei rausgrabbeln
- mistersixt
- Beiträge: 6601
- Registriert: 24.09.2003 14:33:25
- Lizenz eigener Beiträge: GNU Free Documentation License
Perl: Bytes einer Binär-Datei rausgrabbeln
Moin moin,
ich habe hier eine Binär-Datei mit ein paar 1000 Nachrichten, die immer genau 108 Bytes lang sind. Die 108 Byte beinhalten Datenfelder immer gleicher Länge. Wie kann ich jetzt in Perl beispielsweise die Bytes 70 bis 77 einer Variablen zuweisen? Mit split komme ich nicht weiter, soll es substr sein oder gibt es noch eine bessere Methode?
Danke und Gruss, mistersixt
PS: Nächste Frage: wie lese ich eine Binär-Datei ein? Wenn ich die mit while (<>) einlese, erkennt er mir ein paar 1000 Zeilen(!), die Anzahl ist aber unterschiedlich zu der Anzahl der 108-Byte langen Nachrichten .
ich habe hier eine Binär-Datei mit ein paar 1000 Nachrichten, die immer genau 108 Bytes lang sind. Die 108 Byte beinhalten Datenfelder immer gleicher Länge. Wie kann ich jetzt in Perl beispielsweise die Bytes 70 bis 77 einer Variablen zuweisen? Mit split komme ich nicht weiter, soll es substr sein oder gibt es noch eine bessere Methode?
Danke und Gruss, mistersixt
PS: Nächste Frage: wie lese ich eine Binär-Datei ein? Wenn ich die mit while (<>) einlese, erkennt er mir ein paar 1000 Zeilen(!), die Anzahl ist aber unterschiedlich zu der Anzahl der 108-Byte langen Nachrichten .
--
System: Debian Bookworm, 6.11.x.-x-amd64, ext4, AMD Ryzen 7 3700X, 8 x 3.8 Ghz., Radeon RX 5700 XT, 32 GB Ram, XFCE
System: Debian Bookworm, 6.11.x.-x-amd64, ext4, AMD Ryzen 7 3700X, 8 x 3.8 Ghz., Radeon RX 5700 XT, 32 GB Ram, XFCE
Hallo,
glaube read() könnte dir helfen,
liest entweder chars oder Bytes ein.
siehe perldoc -f read
read( DATEIHANDLE, VAR, LENGTH,OFFSET )
Also in etwa:
open(BINDAT, "<:raw", $path) or die "fuck it!";
$offset = 69;
while( read( BINDAT, $var, 7, $offset )){
do something with $var## die Zeile ist kein Perlcode :)
$offset += 108;
}
close(BINDAT);
Viel Spass beim perlen
glaube read() könnte dir helfen,
liest entweder chars oder Bytes ein.
siehe perldoc -f read
read( DATEIHANDLE, VAR, LENGTH,OFFSET )
Also in etwa:
open(BINDAT, "<:raw", $path) or die "fuck it!";
$offset = 69;
while( read( BINDAT, $var, 7, $offset )){
do something with $var## die Zeile ist kein Perlcode :)
$offset += 108;
}
close(BINDAT);
Viel Spass beim perlen
- mistersixt
- Beiträge: 6601
- Registriert: 24.09.2003 14:33:25
- Lizenz eigener Beiträge: GNU Free Documentation License
- mistersixt
- Beiträge: 6601
- Registriert: 24.09.2003 14:33:25
- Lizenz eigener Beiträge: GNU Free Documentation License
Mmmh, habe hier doch einen komischen Effekt, erstmal der Code:
Ab Byte 68 gibt es immer 11 ASCII-Zeichen. Wenn ich das nun laufen lassen (./scan_mls_log.pl | less) bekomme ich ein wildes Durcheinander angezeigt, lenke ich die Ausgabe in eine Datei um, wächst diese ins Unendliche an (sprich, da scheint was zu loopen). Jemand eine Idee, was ich falsch mache?
Danke, mistersixt.
Code: Alles auswählen
#!/usr/bin/perl
#
$DATEI = "/pub/message.dat";
open(BINDAT, "<:raw", $DATEI) or die "Datei oeffnen geht nicht";
$OFFSET = 67;
while( read( BINDAT, $DATENSATZ, 11, $OFFSET )){
print $DATENSATZ;
$OFFSET += 108;
}
close(BINDAT);
Danke, mistersixt.
--
System: Debian Bookworm, 6.11.x.-x-amd64, ext4, AMD Ryzen 7 3700X, 8 x 3.8 Ghz., Radeon RX 5700 XT, 32 GB Ram, XFCE
System: Debian Bookworm, 6.11.x.-x-amd64, ext4, AMD Ryzen 7 3700X, 8 x 3.8 Ghz., Radeon RX 5700 XT, 32 GB Ram, XFCE
Probier mal so,
Könnte sein das du ne Abruchbedingung brauchst in der Schleife:
#!/usr/bin/perl
#
$DATEI = "/pub/message.dat";
open(BINDAT, "<:raw", $DATEI) or die "Datei oeffnen geht nicht";
open(OUTPUT,">> logfile.dat) or die "bla";
$size = (stat($DATEI))[7]; Dateigroesse
$OFFSET = 67;
while( read( BINDAT, $DATENSATZ, 11, $OFFSET )){
print OUTPUT $DATENSATZ . "\n";
$DATENSATZ = "";
$OFFSET += 108;
if( $OFFSET > $size ){ last }
}
close(BINDAT);
Ne andere Sache ist, wenn du ASCII rausfiltern willst,
kannst du mit dem shellprog strings eventuell die Binärdaten
vorher entfernen
$out = `strings $DATEI`;
Könnte sein das du ne Abruchbedingung brauchst in der Schleife:
#!/usr/bin/perl
#
$DATEI = "/pub/message.dat";
open(BINDAT, "<:raw", $DATEI) or die "Datei oeffnen geht nicht";
open(OUTPUT,">> logfile.dat) or die "bla";
$size = (stat($DATEI))[7]; Dateigroesse
$OFFSET = 67;
while( read( BINDAT, $DATENSATZ, 11, $OFFSET )){
print OUTPUT $DATENSATZ . "\n";
$DATENSATZ = "";
$OFFSET += 108;
if( $OFFSET > $size ){ last }
}
close(BINDAT);
Ne andere Sache ist, wenn du ASCII rausfiltern willst,
kannst du mit dem shellprog strings eventuell die Binärdaten
vorher entfernen
$out = `strings $DATEI`;
- mistersixt
- Beiträge: 6601
- Registriert: 24.09.2003 14:33:25
- Lizenz eigener Beiträge: GNU Free Documentation License
Hallo geier,
der Offset scheint nicht zu funktionieren, ich habe jetzt mal ff. gemacht:
Hier bekomme ich als Ausgabe 68 mal "00" und anschliessend die allerersten(!) 11 Byte der Datei (anstatt 11 Byte ab Byte Position 68 ):
ISprich, "00 1f 00 00 00 00 00 03 30 35 3a" sind die ersten 11 Byte und nicht die 11 Byte ab Position 68 . In $hossa steht 11.
Was ist da faul?
der Offset scheint nicht zu funktionieren, ich habe jetzt mal ff. gemacht:
Code: Alles auswählen
#!/usr/bin/perl
#
$DATEI = "/tmp/message.dat";
open(BINDAT, "< $DATEI") or die "Datei oeffnen geht nicht";
binmode(BINDAT);
$OFFSET = 68;
$hossa = read( BINDAT, $DATENSATZ, 11, $OFFSET );
foreach (split(//, $DATENSATZ)) {
printf("%02x ", ord($_));
}
print "\n";
close(BINDAT);
Code: Alles auswählen
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 00 00 00 00 00 03 30 35 3a
Was ist da faul?
--
System: Debian Bookworm, 6.11.x.-x-amd64, ext4, AMD Ryzen 7 3700X, 8 x 3.8 Ghz., Radeon RX 5700 XT, 32 GB Ram, XFCE
System: Debian Bookworm, 6.11.x.-x-amd64, ext4, AMD Ryzen 7 3700X, 8 x 3.8 Ghz., Radeon RX 5700 XT, 32 GB Ram, XFCE
hmmm,
also die Rueckgabe von read ist die Anzahl der gelesenen Bytes,
da is 11 wohl erstmal korrekt.
Mit OFFSET ist allerdings echt bloed:
Hab gerade gelesen dass sich OFFSET auf die Position inder
generierten Variablen und nicht Auf den Dateihandle beziehet.
Vielleicht sollte man die ganze Datei in eine Variable mit OFFSET 0
und LENGTH=Dateigroesse schreiben,
die Variable sollte dann die gesamte Datei in einem String enthalten,
der dann mit substr geparst werden kann.
Naja, nich ganz so schick wie ich dachte
also die Rueckgabe von read ist die Anzahl der gelesenen Bytes,
da is 11 wohl erstmal korrekt.
Mit OFFSET ist allerdings echt bloed:
Hab gerade gelesen dass sich OFFSET auf die Position inder
generierten Variablen und nicht Auf den Dateihandle beziehet.
Vielleicht sollte man die ganze Datei in eine Variable mit OFFSET 0
und LENGTH=Dateigroesse schreiben,
die Variable sollte dann die gesamte Datei in einem String enthalten,
der dann mit substr geparst werden kann.
Naja, nich ganz so schick wie ich dachte
- mistersixt
- Beiträge: 6601
- Registriert: 24.09.2003 14:33:25
- Lizenz eigener Beiträge: GNU Free Documentation License
Hier vielleicht noch ein Versuch
$size = (stat($DATEI))[7];
read( BINDAT, $DATENSATZ, $size, 0 );
foreach (split(//, $DATENSATZ)) {
$readable .= printf("%02x ", ord($_));
}
$end = 3x67;
while( $end < (3x$size) ){ #hex und leerzeichen
$out = substr( $readable, $end, 3x11);
# $out von hex nach ASCII;
print $out . "\n";
$end += 3x67;
}
PS: poste mal die Loesung, ist ein interessantes Ding
$size = (stat($DATEI))[7];
read( BINDAT, $DATENSATZ, $size, 0 );
foreach (split(//, $DATENSATZ)) {
$readable .= printf("%02x ", ord($_));
}
$end = 3x67;
while( $end < (3x$size) ){ #hex und leerzeichen
$out = substr( $readable, $end, 3x11);
# $out von hex nach ASCII;
print $out . "\n";
$end += 3x67;
}
PS: poste mal die Loesung, ist ein interessantes Ding
- mistersixt
- Beiträge: 6601
- Registriert: 24.09.2003 14:33:25
- Lizenz eigener Beiträge: GNU Free Documentation License
Code: Alles auswählen
#!/usr/bin/perl
#
$DATEI = "/tmp/message.dat";
open(BINDAT, "< $DATEI") or die "Datei oeffnen geht nicht";
binmode(BINDAT);
$size = (stat($DATEI))[7];
print $size,"\n";
read( BINDAT, $DATENSATZ, $size, 0 );
close(BINDAT);
$schleife = 0;
while( $schleife < $size ){
print "\$schleife = $schleife\n";
$trader = substr( $DATENSATZ, $schleife + 75, 11);
$is_call = substr( $DATENSATZ, $schleife + 74, 1);
print $trader . "\n";
printf ("%02x\n", ord($is_call));
$schleife += 108;
}
Danke für die Tips geier,
Gruss, mistersixt.
--
System: Debian Bookworm, 6.11.x.-x-amd64, ext4, AMD Ryzen 7 3700X, 8 x 3.8 Ghz., Radeon RX 5700 XT, 32 GB Ram, XFCE
System: Debian Bookworm, 6.11.x.-x-amd64, ext4, AMD Ryzen 7 3700X, 8 x 3.8 Ghz., Radeon RX 5700 XT, 32 GB Ram, XFCE
- godsmacker
- Beiträge: 902
- Registriert: 16.03.2003 21:50:26
- Lizenz eigener Beiträge: Artistic Lizenz
- Wohnort: Chemnitz
-
Kontaktdaten:
Etwas ab vom Thema, aber zum auslesen immer wieder gleich langer Daten kann man uebrigens sehr gut die Spezialvariable oder auch bzw. , wenn man das English Modul verwendet, benutzen.
Dabei werden immer genau 108 bytes lange Strings in $msg gelesen. Damit spart man sich das haessliche herumspielen mit read.
-Florian
Code: Alles auswählen
$/
Code: Alles auswählen
$RS
Code: Alles auswählen
$INPUT_RECORD_SEPARATOR
Code: Alles auswählen
{
local $/ = \108;
open my $fh, $myfile or die $!;
while (my $msg = <$fh>) {
...;
}
}
-Florian
- mistersixt
- Beiträge: 6601
- Registriert: 24.09.2003 14:33:25
- Lizenz eigener Beiträge: GNU Free Documentation License