I have a binary file with a bunch of data blocks stored each after another. The data block is formatted in the following style:
Length [byte] Content Description
2 0xFFFF Data block header
4 Epoch time seconds since 00:00:00 UTC, January 1, 1970
2 value of N Length of data following this value
N Data Data itself
I tried to use unpack, but this was wrong because of the non-fixed length of data.
I need to write a subroutine which will read and parse data blocks (one data block each time the subroutine is called) until the end of file.
The file is using big-endian.
This is what I tried until now:
use strict;
use warnings;
my $filename;
if (! $ARGV[0])
{
die "Input filename is required";
}
sub setFile
{
$filename = $_[0];
}
my $inFile = $ARGV[0];
setFile($inFile);
open INFILE, $filename or die "\nUnable to open input file";
binmode INFILE;
my $nbytes;
while (<INFILE>) {
my( $header, $timestamp_hex, $datalength_hex ) = unpack 'H4 H8 H4', $_;
my $timestamp = hex($timestamp_hex);
my $datalength = hex($datalength_hex);
print "$timestamp $datalength\n";
for (my $i = 0; $i < $datalength; $i++)
{
my $data = unpack 'H', $_;
print "$data";
}
print "\n";
}
close INFILE
or die "Error while closing $filename: $!\n";
<INFILE>
makes no sense. It reads until a newline is found.If you have the whole file in memory, you can use the following:
If we were to extract the header separately from the data, we can save memory and add some error checking.
Reading from a file handle is an extension of the second snippet. If you don't have the whole file in memory, you can use the following:
When using
select
to manage multiple handles, the read must come first, so I'm used to writing it that way. The following is what the above would look like if it was refactored to put the read first: