Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

Creating a binary file problem

by gibsonca (Beadle)
on Apr 05, 2012 at 16:49 UTC ( #963713=perlquestion: print w/replies, xml ) Need Help??
gibsonca has asked for the wisdom of the Perl Monks concerning the following question:

OK I am stuck. Why do I get the error message for each value I try to write?

open(BIN, '>', $fn) or die "Couldn't open file for writing: $!n"; $len = length $gBuf{$bName}[0]; print "len is $len, bname is '$bName' \n\n"; foreach $i (1 ... $len) { # use bigint; printf "\n$i; '$gBuf{$bName}[$i]'\n\n"; binmode BIN; printf BIN pack('C', $gBuf{$bName}[$i]); } close BIN;

the output I get, regardless of my "guesses", is about always the same:

len is 10, bname is 'eps_cm_0_pblk1' 1; '0x00000019' Argument "0x00000019" isn't numeric in pack at line 267. 2; '0x0000001b' Argument "0x0000001b" isn't numeric in pack at line 267. : etc etc 10:

Any help appreciated.

Replies are listed 'Best First'.
Re: Creating a binary file problem
by ikegami (Pope) on Apr 05, 2012 at 17:11 UTC

    The string 0x00000019 is indeed not a number. The integer produced by Perl code 0x00000019 is a number (25), but the string is being passed to pack, not a Perl parser. hex and oct can convert such strings to numbers.

    use strict; use warnings; use feature qw( say ); use Scalar::Util qw( looks_like_number ); my $i = 0x00000019; my $s = '0x00000019'; say $i; say $s; say '---'; say looks_like_number($i) ? 'yes' : 'no'; say looks_like_number($s) ? 'yes' : 'no'; say '---'; say 0+$i; say 0+$s; say '---'; say $i =~ /^0/ ? oct($i) : $i; say $s =~ /^0/ ? oct($s) : $s;
    25 0x00000019 --- yes no --- 25 Argument "0x00000019" isn't numeric in addition (+) at line 21. 0 --- 25 25

    So you want

    pack('C', hex($gBuf{$bName}[$i]))
Re: Creating a binary file problem
by GrandFather (Sage) on Apr 05, 2012 at 21:45 UTC

    Picking up on the "Any help appreciated" comment:

    • Always use strictures (use strict; use warnings;)
    • Use lexical file handles
    • You only need to call binmode once
    • Use Perl for loops to advantage - avoid indexing where it's not needed

    so your code could look like:

    use strict; use warnings; my $fn = "delme.bin"; my $bName = 'eps_cm_0_pblk1'; my %gBuf = (eps_cm_0_pblk1 => ['0x00000019', '0x0000001b']); open my $binOut, '>', $fn or die "Couldn't open '$fn' for writing: $!n +"; binmode $binOut; foreach my $element (@{$gBuf{$bName}}) { print $binOut pack ('C', hex $element); } close $binOut;
    True laziness is hard work
Re: Creating a binary file problem
by Eliya (Vicar) on Apr 05, 2012 at 17:22 UTC

    It's not entirely clear to me what exactly you want to be written to the file, but in case you want to print the values expressed in the hex strings (such as "0x0000001b") as binary values to the file, you could say

    my $hex = "0x0000001b"; print BIN pack('H*', substr($hex,2));

    This would also work for values larger than a Perl number could hold.  In the example above, it would write 4 bytes / 32 bits.

    On a side note, don't use printf, unless you actually specify a format string.

      Given his use of pack 'C', I imagine he wants the single byte 1B, so
      print BIN pack('C', hex($hex));
Re: Creating a binary file problem
by ryber (Acolyte) on Apr 05, 2012 at 17:23 UTC

    It looks like $gBuf{$bName} had been populated with the string representations of these numbers. Can't say for sure, since we don't see that get populated in your code. But I was able to replicate your problem by populating that array like this:

    $gBuf{$bName}[0] = '0x00000019'; $gBuf{$bName}[1] = '0x0000001b'; (etc)

    However, if I populate it this way, I don't see the error:

    $gBuf{$bName}[0] = 0x00000019; $gBuf{$bName}[1] = 0x0000001b;
    so you may want to either go back and fix how those values get in there, or use oct() to convert it to a number. I am guessing you want oct, since you are using pack with 'C', but those numbers look like hex to me.

Re: Creating a binary file problem
by ryber (Acolyte) on Apr 05, 2012 at 17:34 UTC
    Also, are you sure that you want this:
    $len = length $gBuf{$bName}[0];
    and not:
    $len = @{$gBuf{$bName}};
      Indeed, and the indexes start at zero, not one. Actually, one could simply use a foreach loop.
      open(my $fh, '>:raw', $fn) or die "Couldn't open file for writing: $!\n"; for my $hex ( @{ $gBuf{$bName} } ) { printf $fh pack('C', hex($hex)); }

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://963713]
Front-paged by Arunbear
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (7)
As of 2018-05-26 21:51 GMT
Find Nodes?
    Voting Booth?