perlfixed-length-record

How do I read fixed-length records in Perl?


What's the best way to read a fixed length record in Perl. I know to read a file like:

ABCDE 302
DEFGC 876

I can do

while (<FILE>) {
   $key = substr($_, 0, 5);
   $value = substr($_, 7, 3);
}

but isn't there a way to do this with read/unpack?


Solution

  • Update: For the definitive answer, see Jonathan Leffler's answer below.

    I wouldn't use this for just two fields (I'd use pack/unpack directly), but for 20 or 50 or so fields I like to use Parse::FixedLength (but I'm biased). E.g. (for your example) (Update: also, you can use $/ and <> as an alternative to read($fh, $buf, $buf_length)...see below):

    use Parse::FixedLength;
    
    my $pfl = Parse::FixedLength->new([qw(
      key:5
      blank:1
      value:3
    )]);
    # Assuming trailing newline
    # (or add newline to format above and remove "+ 1" below)
    my $data_length = $pfl->length() + 1;
    
    {
      local $/ = \$data_length;
      while(<FILE>) {
        my $data = $pfl->parse($_);
        print "$data->{key}:$data->{value}\n";
        # or
        print $data->key(), ":", $data->value(), "\n";
      }
    }
    

    There are some similar modules that make pack/unpack more "friendly" (See the "See Also" section of Parse::FixedLength).

    Update: Wow, this was meant to be an alternative answer, not the official answer...well, since it is what it is, I should include some of Jonathan Leffler's more straight forward code, which is likely how you should usually do it (see pack/unpack docs and Jonathan Leffler's node below):

    $_ = "ABCDE 302";
    my($key, $blank, $value) = unpack "A5A1A3";