in reply to Re: Reading binary files - program structure
in thread Reading binary files - program structure

An alternative is to your first snippet is to use a hash.
use constant TEMP1 => 'N A10 S'; my %discrete; @discrete{qw( this that theother )} = unpack TEMPL1, read( $file, $size ); print "this:", $discrete{ this };

The constants are more typo resistant, though.

Replies are listed 'Best First'.
Re^3: Reading binary files - program structure
by BrowserUk (Patriarch) on May 20, 2010 at 16:01 UTC

    I did mention hashes along with my blocks of discrete named vars. The main thing I like about the constant method (besides the typo resistance which is good), is that simplicity of in order iteration. Of course you can get that by putting the hash keys into an array, but once you've done that, you're better off using the package stash rather than lexical hash.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Thanks for all the suggestions - now posting an update for anyone who stumbles on this.

      I started with something like almut's state machine but didn't like the way the structure of the file I was trying to read is then encoded into the script structure - feels like poor code/data separation.

      What I've ended up with is more like BrowserUk's suggestions. The crucial point (which I didn't really realise when I originally posted) was that the file format defines how many words should be read for each "variable" in the file, although in most cases that length is actually defined by algebra involving previously-read variables. So we can do something like this:

      my %v; # this hash holds all the data read # define the names of the "variables" to read from the file # *** in the correct order *** my @varnames = qw/this that theother/; # define where the length to read is not a default my %varlengths = ('that' => 2, 'theother' = '$v{this}*2'} foreach my $var (@varnames){ # get the length to read my $readlength; if(! exists($varlengths{$var}) $readlength = 1; # default } else { $readlength = eval($varlengths{$var}); # compute it } # read into %v if ($readlength == 1){ # read a scalar $v{$var} = unpack TEMPL1, read( $file, $readlength ); } else { # read into an anon. array $v{$var} = [ unpack TEMPL1, read( $file, $readlength ) ]; } }

        I think would prefer to use subs rather than string eval here. Eg.

        my %varlengths = ( 'that' => sub(){ 2 }, 'theother' = sub{ $v{this}*2 }, } ... $readlength = $varlengths{$var}->(); # compute it

        Slightly more work, but worth it I think.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.