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

This is a real simple question. How do I open a binary file and search for a 2 byte binary pattern? (specifically FF D9)

Replies are listed 'Best First'.
Re: how to search binary file
by Fletch (Bishop) on Apr 25, 2005 at 16:33 UTC

    Well, you'd open the file, read some of the contents, and see if those contents contain the bytes you're interested in. If not, read more of the file. Lather, rinse, repeat.

    (Post what you've already tried and you'll get more helpful responses.)

Re: how to search binary file
by salva (Canon) on Apr 25, 2005 at 16:43 UTC
    Read the full file in memory and use index() to search for the pattern:
    #/!usr/bin/perl use warnings; use strict; @ARGV or die "usage: $0 file\n"; my $file = shift @ARGV; open my $fh, "<", $file or die "unable to open file"; binmode $fh; # disable "\n" translation my $data; { local $/=undef; $data=<$fh>; } my $pattern=pack('CC', 0xff, 0xd9); my $at=index($data, $pattern); if ($at<0) { print "pattern not found\n" } else { print "pattern found at pos $at\n" }
      No need to slurp the whole thing. Just set $/ to whatever you want to look for and see if it chomps.
      my $fi = "foo\xd9bar\xd9baz\xd9nothing"; open IN, '<', \$fi or die "Die fi!\n"; $/ = "\xd9"; while (<IN>) { print chomp() ? "Found after $_\n" : "Not after $_\n"; }

      Caution: Contents may have been coded under pressure.

        Of course, if the pattern is not found (or found late), your solution still slurps the whole file. The following solution keeps at most {buffer size}+{pattern length)-1 bytes of the file in memory at a time.

        my $pattern = "\xFF\xD9"; open(FILE, "< $file") or die("Unable to open input file: $!\n"); binmode(FILE); # Disable "\n" translation. $/ = \4096; # Arbitrary buffer size. my $block; my $partial = ''; my $base = 0; my $matches = 0; while ($block = <FILE>) { my $lookbehind = $partial . $block; my $pos = -1; for (;;) { $pos = index($lookbehind, $pattern, $offset+1); last if $pos == -1; print("Found a match at ", $base+$pos-length($partial), "\n"); $matches++; } $partial = substr($block, 1 - length($pattern)); $base += length($block); } if ($matches) { print("Found $matches matches.\n"); } else { print("Pattern not found.\n"); }

        Will report overlapping matches.

        Untested.