in reply to Best way to a parse a big binary file
As always TIMTOWTDI, but personally I'd implement it as if I was reading a stream, i.e. with read. Either you give each class the ability to parse the binary representation of itself, or you implement the reading as a single function that just constructs objects of the corresponding class (this would make it easier if the sections aren't entirely independent of each other, like if you've got a checksum over multiple sections). I've chosen the latter here:
use warnings; use 5.012; # for "package BLOCK" syntax package MainHeader { use Moo; has foo => ( is => 'ro' ); } package ExtHeader { use Moo; has bar => ( is => 'ro' ); } package Section { use Moo; has type => ( is => 'ro' ); has quz => ( is => 'ro' ); } my $binfile = "\x01\x06Hello\0" ."\x02\x04\0\x12\x34\x56" ."\x13\x02\xBE\xEF"; sub binread { # helper function for read+unpack my ($fh, $bytes, $templ) = @_; read($fh, my $data, $bytes) == $bytes or die "failed to read $bytes bytes"; return unpack($templ, $data); } open my $fh, '<:raw', \$binfile or die $!; my @packets; while (!eof($fh)) { my ($type, $length) = binread($fh, 2, "CC"); if ($type == 0x01) { my ($foo) = binread($fh, $length, 'Z*'); my $hdr = MainHeader->new( foo => $foo ); push @packets, $hdr; } elsif ($type == 0x02) { my ($bar) = binread($fh, $length, 'N'); my $exthdr = ExtHeader->new( bar => $bar ); push @packets, $exthdr; } elsif ($type == 0x13) { my ($quz) = binread($fh, $length, 'n'); my $sect = Section->new( type => $type, quz => $quz ); push @packets, $sect; } else { die "Unknown packet type $type" } } close $fh; use Data::Dump; dd @packets; __END__ ( bless({ foo => "Hello" }, "MainHeader"), bless({ bar => 1193046 }, "ExtHeader"), bless({ quz => 48879, type => 19 }, "Section"), )
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Best way to a parse a big binary file
by Dirk80 (Pilgrim) on Nov 30, 2019 at 19:33 UTC | |
by haukex (Archbishop) on Nov 30, 2019 at 20:47 UTC | |
by Dirk80 (Pilgrim) on Dec 11, 2019 at 15:41 UTC |