Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

jarich (4909)

jarich
  (email not shown publicly)
http://www.perltraining.com.au/
AOL IM: ManningBear (Add Buddy, Send Message)

I run Perl Training Australia [perltraining.com.au] with pjf [perl.org] and do a lot of the course writing and maintenance. I also organise the courses we run, so if you want one, just ask. I hang around a bit on Perlmonks [perlmonks.org] and also help run Melbourne Perl Mongers [pm.org].

Journal of jarich (4909)

Tuesday February 26, 2008
12:50 AM

File::Temp, binary mode and text files

[ #35761 ]

In my day job, amongst other things, I write training materials and run courses for Perl Training Australia. We've only recently added File::Temp to our course notes, and since we allow our attendees to use either our portable training server (Linux) or their desktop (often Windows) we've hit a problem.

File::Temp's tempfile isn't portable for text files. This is because it opens them using sysopen and the O_BINARY flag (where available). This means that newlines printed to the file aren't converted into the operating system's preferred end of line character(s).

This shouldn't have been a surprise, it's in the documentation:

BINMODE

The file returned by File::Temp will have been opened in binary mode if such a mode is available. If that is not correct, use the binmode() function to change the mode of the filehandle.

Note that you can modify the encoding of a file opened by File::Temp also by using binmode().

However the binmode documentation rightly points out:

For the sake of portability it is a good idea to always use it when appropriate, and to never use it when it isn't appropriate.

I know I can tell the Windows students to write:

binmode($tmp_fh, ":crlf" );

after their call to tempfile(), but it's still not going to be portable. Creating a tempfile doesn't look like it should be a special case, and in my experience, it's usually safe to tell (fairly computer and operating system savvy) students that if it looks portable, it should be.

Is there a layer I can give to binmode to tell it to go back to treating the file as a text file with all the special magic regarding newlines that should happen? I essentially want a: binmode($tmp_fh, ":default");

I can always write File::Temp::Text which doesn't use O_BINARY but that's another, non-standard, module for the students to have to install.

I originally brought this question up on PerlMonks but I'm still hoping for a magic answer that lets me teach students a portable way of handling temporary text files where the file name is available. (Yes, I know about open with an undef filehandle).

Any hints?

Thanks, jarich

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Is there a layer I can give to binmode to tell it to go back to treating the file as a text file with all the special magic regarding newlines that should happen? I essentially want a: binmode($tmp_fh, ":default");
    Could you use PerlIO::eol [cpan.org]?
  • I'm not sure I understand the concern as long as the temporary files are actually temporary -- meaning that they aren't going to persist past the program or be transferred to another machine. So what if the newlines are LF instead of CRLF? As long as Perl treats it all as "\n" when reading and writing, isn't that good enough?

    -- dagolden
    • One of my common uses of temporary files is to allow me to make changes to a whole file, know that that all succeeded and then replace said file. For example, to reverse each line in a file I might write:

      # Reverses each line in a file
      use File::Temp qw(tempfile);
      use File::Copy qw(move);
      use Fatal qw(open close move);

      # Open files
      my $filename = shift or die "Usage: $0 filename";
      open(my $in, "<", $filename);
      my ($tmp_fh, $tmp_name) = tempfile();

      # Read line in, remove newline, reverse and print it
      while(