Re: reading a few bytes into a file



Scott Haneda wrote:

Hi Rob, thanks for your reply. This is my first adventure into perl,
and I am a bit stumped. I have experience in a few web scripting
languages, but this is a little new to me.

Your script does work, and returns a number, but not the correct one,
and I think it has to do with my in file being in a strange format.
It is a email Inbox, the message count is told to me by the developer
to be 4 bytes in, 4 bytes long, and a big endian value. I just want
the mailbox count of messages out of it, which the C code below did in
fact do. I just have issues moving that C binary to other machines,
and perl will be more universal.

I zipped a file and put it up, it should have 8 messages in it. The
developer of the email server is not as forthcoming with help in this
regard, so I am at a loss for a lot of data on the format of the file.

There is a sample file here:
http://www.newgeo.com/web/misc/62315-testbox.zip

If you would not mind taking a look at it, I will post a follow up to
the list explaining how it all works, as soon as I understand it.

I put a few comments inline below about your code.

Hello, I have this small C app that someone wrote for me ages ago,
and
am tired of it breaking every time I move it around to various
systems, I will include it below.

I am hoping I can do this in perl, as a one liner, were it will
read a
the first 4 bytes of a file, grab 4 bytes out of the file, which is a
big endian value, and return that as an int to me.

Here is the basic C app I have been using:

#include <stdio.h>
#include <libkern/OSByteOrder.h>

int main (int argc, char *argv[]) {
FILE* fd;
char buffer[8];
unsigned long int dv;

//open the file
fd = fopen(argv[1], "r");
printf("Filename: %-50s", argv[1]);

fread(buffer, 1, sizeof(buffer), fd);
dv = OSReadBigInt32(buffer, 4);

// print the decimal value
printf(" Value: %ld\n", dv);

return 0;
}
use strict;
use warnings;

my $file = shift;

open my $fh, '<', $file or die $!;
print "Filename: $file";

Is there no need to close the file handle? If not, what harm is there
in leaving it open?

my $buffer;
my $count = read $fh, $buffer, 4 or die $!;
die "Insufficient data in file" unless $count >= 4;

my $dv = unpack 'N', $buffer;
print " Value: $dv\n";

I just read the docs on unpack, and I do not follow what the purpose
is here?

OK, first of all the correction. I didn't know the function of OSReadBigInt32
and assumed the second parameter was a byte count. It seems that it's actually a
byte offfset, so we need to read in eight bytes to start with and convert the
last four to a big-endian longword. Version 0.2 is below and I hope it gives you
the right value this time.

Now for the questions.

- Using a lexical scalar file handle conveniently closes the file when the
scalar goes out of scope. In this case it will be closed at the end of the
program, but it's a good habit to get into to restrict file operations to a
small scope and rely on automatic closure. Something like this, for example

my $first_line;
{
open my $fh, '<', $infile or die $!;
$first_line = <$fh>;
}

which will open the file, read the first line and close it, leaving only the
required data still existing.


- The bulk of the documentation on 'unpack' is in

perldoc -f pack

and the new unpack format moves to a character offset of 4 (@4) and extracts a
32-bit big-endian integer (N).

Finally, please post to the group and not directly to me, so that others can
both help and be helped by the dialogue. Thanks.

HTH,

Rob




use strict;
use warnings;

my $file = shift;

open my $fh, '<', $file or die $!;
print "Filename: $file";

my $buffer;
my $count = read $fh, $buffer, 8 or die $!;
die "Insufficient data in file" unless $count >= 8;

my $dv = unpack '@4 N', $buffer;
print " Value: $dv\n";
.



Relevant Pages

  • Re: Using References to Formats, Examining Scalars With Devel::Peek
    ... the format to be able to refer to it by another name didn't occur to me. ... Seems most of the fields are the same as for the rest of the Perl ... from integer to double and how frequently the string portions are updated. ... Using an operator or a built-in with a double and an int usually converts ...
    (comp.lang.perl.misc)
  • Re: EBCDIC-ASCII Conversation
    ... > part's of the files are in packed format I have to do this in perl. ... your records, and unpack ... those into signed decimal format before continuing. ...
    (comp.lang.perl.misc)
  • Re: EBCDIC-ASCII Conversation
    ... >> part's of the files are in packed format I have to do this in perl. ... Are you saying that these data records contain ... > your records, and unpack ...
    (comp.lang.perl.misc)
  • Re: Remove zero from 01, 02, etc.
    ... SB> The only reason I knew that int() worked properly in the OP's case is ... SB> due to a prior (ie not long after my first exposure to Perl) experience ... SB> it's own code to format it. ...
    (perl.beginners)
  • Re: Passing structure from perl to C.
    ... int addStruct_wrapper{ ... How do I access the members of the structure that the C routinue ... returns in Perl. ... Well, unpack, but if you're writing an XSUB anyway you might as well ...
    (comp.lang.perl.misc)