Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I was given a Binary Data File consisting of account information from an old system. I know that the first 4 bytes is the time the account was created, the next 4 bytes is the length of the employee information (which is stored in plain text and easily delt with).

The file consists of 1 record right after the other, so I can not garentee a delimiter of some sort, other than knowning the length of the data being stored.

My question is, where do I even begin. I am using the following code as a test, just trying to pull out the data, but am having no luck getting something usable. I am starting small, once I figure out how to get the information to something useful, the rest will be a snap.
#!/usr/bin/perl -w use strict; my $data_file = "record"; open(FILE,"$data_file") or die $!; binmode(FILE); read(FILE,my $time,3,0); print "$time \n"; close(FILE);

Replies are listed 'Best First'.
Re: Binary Data File
by broquaint (Abbot) on Oct 26, 2002 at 13:50 UTC
    Why not take advantage of the $/ variable like so
    open(my $fh, $data_file) or die("ack: $!"); binmode($fh); my @records; { # see. the man perlvar for more info on $/ local $/ = \4; push @records, [ $_, scalar <$fh> ] while <$fh>; }
    Now you'll have an array of arrays, where each array contains a pair of 4 byte records.
    HTH

    _________
    broquaint

Re: Binary Data File
by BrowserUk (Patriarch) on Oct 26, 2002 at 13:59 UTC

    There are various ways of tackling this. You should take a look at the perlvar description of $/ (search for $INPUT_RECORD_SEPARATOR). As well as being able to be set to a string such as "\n" etc. it can also be set to a reference to a number as in local $/=\20; This will then cause the diamond operator references to a filehandle <FILEHANDLE> to read the file in chunks of n chars.

    You can also process fixed length records from a file using pack and unpack, or indeed using read as your snippet shows.

    If you would post a description of the record format it would be possible for us to help you narrow down the best choice and provide a little sample code that would help you further.


    Cor! Like yer ring! ... HALO dammit! ... 'Ave it yer way! Hal-lo, Mister la-de-da. ... Like yer ring!
Re: Binary Data File
by Aristotle (Chancellor) on Oct 26, 2002 at 14:26 UTC

    Minor note first: why did you put $data_file in quotes? There is no reason to do so except in a few very special cases. Otherwise, it's useless extra effort.

    Now if I understood your specification correctly, you want this:

    #!/usr/bin/perl -w use strict; my $data_file = "record"; open(FILE, "<", $data_file) or die $!; binmode(FILE); my $file_len = -s FILE; while($file_len > tell FILE) { read FILE, my $fixed, 8; my ($date, $rec_len) = unpack "L2", $fixed; read FILE, my $empl_info, $rec_len; # ... processing here } close FILE;
    The key is the second read, which uses the just decoded length to determine how much to read. Instead of L2, you may need another format; see perldoc -f unpack and perldoc -f pack. (See perldoc -f -X and perldoc -f tell if you don't see just how that loop terminates.)

    Makeshifts last the longest.