cut in Binärdatei / Binärdatei aufspalten
Hallo Liste, ich suche seit einiger Zeit nach einer Möglichkeit, Teile aus einer Binärdatei herauszuschneiden. Ich hatte gehofft, das ginge mit cut oder mit dd, aber leider hat das bei mir nicht funktioniert. Die Datensaätze in den Binärdateien, um die es geht, haben alle eine feste Länge, sagen wir mal 8700 Bytes. Der gesamte Datenbestand umfasst 38000 Sätze, so dass die Datei insgesamt 330.600.000 Bytes groß ist. Ich möchte jetzt aus dieser Datei die Bytes 1 bis 1000, 3000 bis 3500 und 8500 bis 8700 ausschneiden und damit einen neuen Datensatz mit der Länge 1700 Bytes erzeugen. Die gesamte Datei hätte dann die Größe 64.600.000 Bytes. Wie kann ich so etwas machen? Vielen Dank für Eure Hilfe -- Mit freundlichen Grüßen Jens Grüntjes
On Thursday 14 July 2005 11:05, Jens Gruentjes wrote:
Hallo Liste,
ich suche seit einiger Zeit nach einer Möglichkeit, Teile aus einer Binärdatei herauszuschneiden. Ich hatte gehofft, das ginge mit cut oder mit dd, aber leider hat das bei mir nicht funktioniert.
Die Datensaätze in den Binärdateien, um die es geht, haben alle eine feste Länge, sagen wir mal 8700 Bytes. Der gesamte Datenbestand umfasst 38000 Sätze, so dass die Datei insgesamt 330.600.000 Bytes groß ist. Ich möchte jetzt aus dieser Datei die Bytes 1 bis 1000, 3000 bis 3500 und 8500 bis 8700 ausschneiden und damit einen neuen Datensatz mit der Länge 1700 Bytes erzeugen. Die gesamte Datei hätte dann die Größe 64.600.000 Bytes.
Wie kann ich so etwas machen?
Mit Perl ist es ein Einzeiler: perl -ne 'BEGIN{$/=\8700;} print substr( $_, 0, 1000 ), substr( $_, 3000, 500 ), substr( $_, 8500, 200 );' <input >output Ich habe das Ganze etwas vereinfacht getestet: perl -e 'for( 1..10 ) {$i=0;print( map( {chr($_+ ++$i)} (0x20)x87 ) );}' | perl -ne 'BEGIN{$/=\87;} print substr( $_, 0, 10 ), substr( $_, 30, 5 ), substr( $_, 85, 2 ), "\n";' Das erste Perl-Kommando erzeugt 10x die ersten 87 ASCII Zeichen nach dem Blank, der zweite Perl-Aufruf schneidet aus jedem Record, der 87 Bytes lang ist, die Zeichen 1-10, 30-35 und 85-87 heraus. Das Newline am Ende des print-Statements ist nur zur besseren Übersicht. Es geht aber vielleicht auch mit der bash: perl -e 'for( 1..10 ) {$i=0;print( map( {chr($_+ ++$i)} (0x20)x85 ), "\n\n" );}' | (IFS=;while read -n 10 -d '' a && read -n 20 -d '' dummy && read -n 5 -d '' b && read -n 50 -d '' dummy && read -n 2 -d '' c; do echo -n $a$b$c; done) Das Perl-Kommando erzeugt wieder 87 Bytes lange Records, die die Subshell mit read liest. Zum Test habe ich in die Records auch Newlines eingebettet. Mit IFS='' und -d '' stören sie nicht. Ich nehme aber an, dass es durchaus "böse" Zeichen gibt, mit denen read vorzeitig abbricht, z.B. '\0'. Torsten
Hallo,
danke das klappt schon sehr gut. Ich hab deinen Vorschlag mal mit einer meiner
Dateien getestet und es sieht gut aus. Wir haben hier auch ein
Programm, das so
etwas macht, allerdings nur auf Windows-Rechnern und ohne Quelltext.
Die Datei,
die mit deinem Vorschlag entsteht, ist identisch mit der, die mit dem Programm
auf ner Windows-Kiste entsteht.
Eine Frage noch zu dem Skript. Ich bin kein Experte in Perl, dachte
aber bisher,
dass mit Perl hauptsächlich ASCII-Dateien bearbeitet werden können. Deshalb
war ich der Meinung, dass Perl die eingelesenen Zeichen in irgendeiner Form
interpretiert, was für meine Zwecke eigentlich eher schädlich wäre. Kann es
Konstellationen in den Binärdateien geben, mit denen Perl nicht klar kommt?
Ich würde den Einzeiler gern als Skript benutzen, dem ich die auszuschneidenden
Passagen als Parameter übergebe. Gibt es da ein Paket für Perl, mit dem ich
das machen kann? Also so was wie 'getOpt.h' in C? Oder anders gefragt, was
würdet ihr da benutzen?
Danke für die Hilfe
--
Mit freundlichen Grüßen
Jens Grüntjes
Zitat von Torsten Foertsch
Mit Perl ist es ein Einzeiler:
perl -ne 'BEGIN{$/=\8700;} print substr( $_, 0, 1000 ), substr( $_, 3000, 500 ), substr( $_, 8500, 200 );' <input >output
Torsten
use Getopt::Long; use Getopt::Std; Manpages gibt's dazu. -- Viele Grüße ------------------------------------------------------------------------ Michael Behrens
On Thursday 14 July 2005 13:30, Jens Gruentjes wrote:
Eine Frage noch zu dem Skript. Ich bin kein Experte in Perl, dachte aber bisher, dass mit Perl hauptsächlich ASCII-Dateien bearbeitet werden können. Deshalb war ich der Meinung, dass Perl die eingelesenen Zeichen in irgendeiner Form interpretiert, was für meine Zwecke eigentlich eher schädlich wäre. Kann es Konstellationen in den Binärdateien geben, mit denen Perl nicht klar kommt?
Für alle Fälle kannst Du noch ein "use bytes" oder entsprechend -Mbytes mit reinschreiben. Auch "binmode STDIN" und "binmode STDOUT" sind evtl. sinnvoll. perl -Mbytes -ne 'BEGIN{$/=\8700; binmode STDIN; binmode STDOUT;} print( (unpack "A1000A2000A500A5000A200", $_)[0,2,4] );' Die 3 substr Anweisungen kann man auch durch ein unpack ersetzen. Das ist in Deinem Fall wahrscheinlich besser, denn das Format a heißt eindeutig: "A string with arbitrary binary data". Torsten
participants (3)
-
Jens Gruentjes
-
Michael Behrens
-
Torsten Foertsch