Beefy Boxes and Bandwidth Generously Provided by pair Networks Frank
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Re: Temporary text files with File::Temp

by bcrowell2 (Friar)
on Feb 26, 2008 at 04:09 UTC ( #670224=note: print w/ replies, xml ) Need Help??


in reply to Temporary text files with File::Temp

I believe Active State Perl on Windows implements the POSIX module -- http://aspn.activestate.com/ASPN/docs/ActivePerl/5.8/lib/POSIX.html -- so maybe:

use POSIX qw(tmpnam); my $tmp_name = tmpnam();

In general, I think it's a laudable goal to write code that's 100% portable, and works properly on all platforms without any special casing. Realistically, I don't think that's possible for any perl program of any significant complexity. Maybe it's doable if everything your students are writing is just short exercises. The one time I wrote a cross-platform perl app to run on both Windows and Unix, all I managed to do was isolate all the OS-dependent stuff in one file, but I did have to have a bunch of special casing in that file. I remember lots of hassles with, e.g., filename globbing.


Comment on Re: Temporary text files with File::Temp
Download Code
Re^2: Temporary text files with File::Temp
by jarich (Curate) on Feb 26, 2008 at 04:45 UTC

    I think it's a laudable goal to write code that's 100% portable, and works properly on all platforms without any special casing. Realistically, I don't think that's possible for any perl program of any significant complexity.

    To a large extent, I agree. It can be very difficult to write Perl programs of significant complexity that are 100% portable, especially if you're not practiced in doing such.

    However, I'm not talking about writing Perl programs of any complexity in this question. I don't think it should be hard to open a temporary text file and be able to print stuff including newlines to it, and have the right thing happen. Regardless of operating system. This is an introductory course to Perl after all.

    My students should be able to write:

    # Reverses each line in the given file # and replaces that file with the reversed copy use File::Temp qw(tempfile); use File::Copy qw(move); use Fatal qw(open close move); my $filename = shift or die "Usage: $0 filename"; open(my $in, "<", $filename); my ($tmp_fh, $tmp_name) = tempfile(); while(<$in>) { chomp; print {$tmp_fh} scalar(reverse($_)), "\n"; } close $in; close $tmp_fh; move($tmp_name, $filename);

    and expect it to work flawlessly on any operating system that has Perl installed. There's nothing in that code which would suggest to a Perl novice (or me until last week) that that code isn't portable.

    I realise that it's fundamentally a question of what the logical default case should be. File::Temp has several choices; always binmode the file, never binmode the file, binmode the file if passed a flag, don't binmode the file when passed a flag. They've chosen the first, I was hoping there might have been an undocumented way to get the last.

    Alternately if there is a special layer I can pass to binmode itself to say "treat as text" so that Perl can do it's special text-file magic by translating \n to the appropriate thing; I'd love to hear about that. This isn't achieved by using the :crlf layer, because that layer is Windows specific, and won't do the right thing under the *nixes.

    Any other suggestions?

    thanks, jarich

      The problem is that the default for normal open and the default for temfile is different.

      Teach to always specify the mode of a file, text or binary, because on some platforms it matters. For that matter, be clear about the character encoding too.

      Maybe you should update the File::Temp module.

      Or, write your own tempfile function that calls the regular open. That way you have consistent semantics. That's what I do.

      —John

      jarich, you wrote:

      "Alternately if there is a special layer I can pass to binmode itself to say "treat as text" so that Perl can do it's special text-file magic by translating \n to the appropriate thing; I'd love to hear about that."

      I was recently investigating the use of the I/O layers and seem to recall that there may be a way to do what you asked about. But I'm by no means an expert on the topic so it isn't something I've got much experience with.

      But wouldn't that constitute exactly what you said you didn't want...special processing for each environment? And wouldn't that defeat your goal of keeping it simple for your students?

      ack Albuquerque, NM

        It depends on what the special layer was. For example if I could write:

        binmode($fh, ":text");

        And have it do the right thing on all systems, it'd be an okay solution. Of course, the best place to fix this is still in File::Temp, because teaching the students that they'll need two commands isn't quite as cool as just giving them one.

        I've looked at the File::Temp code, and it looks pretty easy to patch, so as soon as I have time and access to a Windows box, I'll be working on that. Probably mid-April.

Re^2: Temporary text files with File::Temp
by jarich (Curate) on Feb 26, 2008 at 06:05 UTC

    Regarding POSIX's tmpnam, you might want to check the documentation on that too:

    tmpnam

    Returns a name for a temporary file.

    $tmpfile = POSIX::tmpnam();

    For security reasons, which are probably detailed in your system's documentation for the C library tmpnam() function, this interface should not be used; instead see File::Temp.

    With respect to actually writing portable code, it's probably gotten a lot easier since you tried it. File::Spec, File::Copy, improvements to glob and File::Glob etc, all help.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://670224]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (10)
As of 2014-04-20 17:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (485 votes), past polls