How should I use Perl's File::Temp?
Asked Answered
E

5

12

I would like to create a temp file, write to the file-handle then call an external program with the filename.

The problem is I would normally want to close the file after writing to it and before calling the external program, but if I understand correctly close-ing a tempfile() causes it to be removed.

So what is the solution here?

Eckman answered 18/10, 2010 at 13:16 Comment(3)
It sounds like you don't actually want a temporary file.Willson
but I do. I call the external program from within my script. After it's done, I don't need the file anymore.Eckman
Actually File::Temp does not unlink the file after creation (in contrast to IO::File->new_tmpfile).Orthicon
A
11

Write to the temp file with buffering turned off. Call the external program before you close the file in the Perl script, and the external program will be able to read everything you have written.

use File::Temp qw(tempfile);
use IO::Handle;

my ($fh, $filename) = tempfile( $template, ... );

... make some writes to $fh ...

# flush  but don't  close  $fh  before launching external command
$fh->flush;
system("/path/to/the/externalCommand --input $filename");

close $fh;
# file is erased when $fh goes out of scope
Antipodes answered 18/10, 2010 at 13:24 Comment(3)
I have a uncontrollable repulsion from using open files... but this seems to work.Eckman
Where is $template defined and what is it defined to: not even the official docs for File::Temp make mention of this elusive piece of crap.Apostatize
It is any string that ends with 4 or more consecutive X'sAntipodes
S
6

From http://perldoc.perl.org/File/Temp.html:

unlink_on_destroy

Control whether the file is unlinked when the object goes out of scope. The file is removed if this value is true and $KEEP_ALL is not.

   1. $fh->unlink_on_destroy( 1 );

Default is for the file to be removed.

Try to set it to 0.

Sailcloth answered 18/10, 2010 at 13:22 Comment(0)
M
1

with OOP interface of File::Temp you can do:

my $cpp =  File::Temp->new;
print $cpp "SOME TEXT";
$cpp->flush;

`cat $cpp`;
Marigolda answered 29/12, 2017 at 16:56 Comment(0)
I
0

closing is better than flushing, because of possible deadlock. File::Temp tempfile is opened with lock

{
    my $tmp = File::Temp->new(
        UNLINK => 0
    );

    select $tmp;
    say 123;
    select STDOUT;

    # $tmp->flush;
    close $tmp;

    say 'slurp >> ', path($tmp->filename)->slurp;
}

{
    my $tmp = Path::Tiny->tempfile(
        UNLINK => 0
    );

    my $fh = $tmp->filehandle('+>');

    select $fh;
    say 123;
    select STDOUT;

    # $fh->flush;
    close $fh;

    say 'slurp >> ', $tmp->slurp;
}
Imaret answered 21/3, 2019 at 7:20 Comment(0)
O
0

As I had the same scenario, here is what I found after some reading and experimenting:

my $XML;
# ...
if ($XML) {
    use File::Temp;
    my $tf = File::Temp->new('TEMPLATE' => 'monXXXXXX', 'DIR' => '/tmp',
                             'SUFFIX' => '.xml');

    $tf->print($XML);
    # in reality a more complex command than "cat" is being used
    $tf->close() and system(qw(/usr/bin/cat), $tf->filename());
    # ...
}

The point here is that using $tf after close to get the filename, prevents the file from being deleted (i.e.: $tf being garbage-collected and DESTROYed). I don't need the temporary file any more after system, so it's OK if it's removed after that call.

I theory Perl could garbage-collect $tf immediately after the filename had been determined (and thus the external command would not find it any more), but that's not how Perl works. If paranoid, you could pass $tf to some function after system, thus preventing garbage collection before...

Orthicon answered 5/10, 2023 at 10:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.