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

Hi Monks, I have a file that is mixed with ascii text and binary. The binary part of the file is delimited by "Binary:\n". Then there is binary data that must be read 64 bits at a time. The binary data is too large to be split into a separate file or copy, so I would like to do this in one swoop. The following code does not work, it appears as if I cannot switch to binmode once I encounter the binary section of the file? Again, pretend that the binary portion is large so this needs to be done efficiently. Thanks in advance!

#!/usr/local/bin/perl use strict; use warnings; my $raw_file="spectrebin.raw"; open (FILE,$raw_file); foreach my $line (<FILE>) { if ($line=~/^Binary:/) { #Switch to binary mode #NOTE: If you comment this line in, # it works but starts reading the file from the # start, which I do not want. I want it to # read only the binary portion #open (FILE,$raw_file); binmode(FILE) or die "ERROR> Could not read binary file"; my $buffer; while ((read (FILE, $buffer, 64))!=0) { my $binary = unpack("B64",$buffer); printf "Binary: $binary\n"; } #Do not read the binary part as ascii last; } else { #the ascii part printf "ASCII: $line"; } }

Replies are listed 'Best First'.
Re: Mixed text and binary file
by davido (Cardinal) on Feb 20, 2014 at 20:28 UTC

    Set binmode at the beginning, and set $/ = 'Binary:';. Do a single read from the filehandle with $text = <FILE>. Then set $/=\64;, and subsequent reads with $chunk = <FILE> will be 64 bytes at a chunk.

    Another approach is to use tell once you've found the exact location of Binary:, then seek and read from that point. In this case, I would still start out by setting $/ = 'Binary:', so that I wouldn't have to worry about counting backwards from the next apparent newline to 'Binary:'.


    Dave

      Thanks! Based on your feedback this works. It never ceases to amaze me what perl can do! I'm first preserving the ASCII portion of the file other purposes.

      #!/usr/local/bin/perl use strict; use warnings; my $raw_file="spectrebin.raw"; open (FILE,$raw_file); foreach my $line (<FILE>) { if ($line=~/^Binary:/) { #Do not read the binary part as ascii printf "ASCII: $line"; last; } else { #the ascii part printf "ASCII: $line"; } } close(FILE); open (FILE,$raw_file); binmode(FILE) or die "ERROR> Could not read binary file"; $/ = "Binary:\n"; my $text = <FILE>; my $buffer; while ((read (FILE, $buffer, 64))!=0) { my $binary = unpack("B64",$buffer); printf "Binary: $binary\n"; } close(FILE);
        It never will cease to amaze you ... what Perl can do ... This language has been called a Swiss-Army Knife, and it deserves the accolade.