in reply to Problem with Pack

You fell prey to the idiosyncrasies of C and DOS, who together make a difference between text files and binary files.

Each file is by default in text mode, which means that every byte aequivalent to \n is translated into the byte sequence 0d 0a by Perl or by the underlying OS.

The solution is to always use binmode() on files that you want to handle as binary files.

So, use the following idiom for files that you want Perl to handle as binary files. It dosen't make any difference on systems that don't distinguish text and binary files :

use strict; # Always use strict local *FILE; # This declares FILE as a local variable. # This is NOT necessary for variables with # UPPERCASE names, as strict # ignores these, see [jcwren]s post # below for an excellent explanation. # But localizing a file variable prevents # us from messing up other variables of # the same name. open FILE, "> $filename" or die "Couldn't create '$filename': $!\n"; binmode FILE; # do your stuff close FILE;

Update : In the code above, there was the following statement, which is not true (I didn't know that) :

local *FILE; # With strict, we need to predeclare *FILE # (not necessary for builtin file handles such + as STDIN)
I've changed my main CODE block to reflect what actually happens and why I think that using local is still a good idea :-). Thanks to jcwren, who pointed this out to me (in the below post).

Replies are listed 'Best First'.
(jcwren) Re: Problem with Pack
by jcwren (Prior) on Sep 22, 2000 at 17:54 UTC
    In Corion's most excellent answer, there is an extra line of code, with an incorrect comment.

    The local *FILE isn't actually required. The following snippet works with no errors. Perl has special handling for all uppercase names, which it perceives to be a typeglob. File handles, such as 'FH' and 'FILE' in the two examples, are actually typeglobs. If you change the 'FH' to 'fh' below, it will fail with bareword construct warnings.

    That being said, since typeglobs are global to the program, using 'local' will localize it to the subroutine (presuming that you're in one, of course), and protect any ones used globally.

    The best way to do this, for other than quick'n'dirty stuff, is to use IO::Handle. Using a handle created with IO::Handle, you can pass the handle around as a scalar, not have to worry about namespace collision, etc.

    If you have Advanced Perl Programming, chapter 3, talks about 'Perl Variables, Symbol Table, and Scoping', and section 4 talks about file handles explicitly.
    #!/usr/local/bin/perl -w use strict; open (FH, ">myworld") || die $!; binmode FH; print FH "Hello, world\n"; close FH;
    --Chris

    e-mail jcwren
      I use lexically scoped filehandles all of the time without ever digging into the IO::* family. The three basic techniques are to use Symbol and call gensym, construct your own symbol with do {local *FOO}, or use 5.6 which autovivifies handles for you.

      I generally am not on 5.6 so I tend to either use Symbol or do it myself. (Usually Symbol.)