Temporäre Dateien sicher erzeugen - File::Temp

Veröffentlicht von Thomas Fahle am (Permalink)

Ooops

Etwas wie

open TMPFILE ">/tmp/work.$$";
print TMPFILE ...

ist praktisch immer ein Programmierfehler. Hier wird zum Einen der unsichere Aufruf von open() mit zwei Argumenten statt der sichereren Form mit drei Argumenten verwendet und zum Anderen ist das Muster zur Erzeugung der temporären Datei viel zu einfach.

Bordmittel sind reichlich vorhanden

Perl stellt zur Erzeugung temporärer Dateien einige sichere Methoden zur Verfügung, z.B. anonyme temporäre Dateien und das Standardmodul File::Temp.

Anonyme temporäre Dateien

Seit Perl 5.8 besteht die Möglichkeit anonyme temporäre Dateien zu erzeugen, indem open() anstelle eines Dateinamens undef als Parameter übergeben wird.

Beispiel:

#!/usr/bin/perl
use strict;
use warnings;

my $fh;

open($fh,"+>",undef) or die "Could not open temp file - $!";

	# Daten in Temp-Datei schreiben

foreach my $line ( 1 .. 5 ) {
        print $fh "$line\n";
}

	# Daten aus Temp-Datei lesen

	# Zum Anfang der Datei
seek($fh, 0, 0);

while(<$fh>) {
	print;
}

close($fh) or die "Could not close temp file - $!";

exit();

File::Temp

File::Temp ist seit Perl 5.6.1 ein Standardmodul, d.h. es wird mit Perl ausgeliefert und läuft auf jeder Plattform, die von Perl unterstützt wird.

Dokumentation und API werden selbst von sehr gutmütigen Menschen bestenfalls als verwirrend bezeichnet.

Nachfolgend einige Beispiele, die Ihnen den Einstieg in File::Temp schrittweise erleichtern sollen.

Beispiel 1

Dieses Beispiel verwendet die Standardwerte von File::Temp.

#!/usr/bin/perl
use warnings;
use strict;

use File::Temp qw/ tempfile tempdir /;

my ($dir, $fh, $filename, $line);

$dir = tempdir( CLEANUP =>  1 );
($fh, $filename) = tempfile( DIR => $dir );

binmode($fh);

print "Verzeichnis: $dir\n";
print "Datei:       $filename\n";

	# Daten in Temp-Datei schreiben
foreach $line ( 1 .. 5 ) {
	print $fh "$line\n"; 
}

        # Daten aus Temp-Datei lesen
        # Zum Anfang der Datei
seek($fh,0,0);

while ($line = <$fh>) {
	print $line;
}

exit();

Ausgabe unter Linux

Verzeichnis: /tmp/ZT4Udprbvy
Datei:       /tmp/ZT4Udprbvy/4DOBscRn7o
1
2
3
4
5

Ausgabe unter Windows

Verzeichnis: C:\DOKUME~1\tf\LOKALE~1\Temp\LzIqqKVIga
Datei:       C:\DOKUME~1\tf\LOKALE~1\Temp\LzIqqKVIga\SL1tNeuIvV
1
2
3
4
5

File::Temp schreibt nicht einfach in eine Datei mit zufällig gewähltem Dateinamen, sondern legt zunächst ein Verzeichnis mit zufällig gewähltem Namen an, in dem dann die Datei angelegt wird.

Die Anweisung

$dir = tempdir( CLEANUP =>  1 );

sorgt dafür, das das temporäre Verzeichnis einschließlich der darin enthaltenen Dateien beim Beenden des Programms komplett gelöscht wird. Dieses Verhalten kann abgeschaltet werden durch

$dir = tempdir( CLEANUP =>  0 );

Aufräumen müssen Sie jetzt selbst.

Beispiel 2: Verzeichnis für temporäre Dateien festlegen

Wer vermeiden möchte, das File::Temp temporäre Dateien unterhalb der systemüblichen Verzeichnisse anlegt, z.B. wenn /tmp auf einer anderen Partition oder Festplatte liegt oder bei "Shared Webhosting", kann ein (bereits bestehendes) Verzeichnis über den Parameter DIR als Speicherort festlegen.

#!/usr/bin/perl
use warnings;
use strict;

use File::Temp qw/ tempfile tempdir /;

my ($dir, $mydir, $fh, $filename);

$mydir = './mydir'; 
mkdir $mydir unless -d $mydir;

$dir = tempdir( DIR => $mydir, CLEANUP =>  0 );

($fh, $filename) = tempfile( DIR => $dir );


print "Verzeichnis: $dir\n";
print "Datei:       $filename\n";

exit();

Das Programm erzeugt folgende Ausgabe:

Verzeichnis: mydir/2bQHkxZFqY
Datei:       mydir/2bQHkxZFqY/lKyMkclvzR

Beispiel 3: Extension für Dateinamen setzen

Dateiendungen lassen sich über den Parameter SUFFIX festlegen.

#!/usr/bin/perl
use warnings;
use strict;

use File::Temp qw/ tempfile tempdir /;

my ($dir, $mydir, $fh, $filename, $suffix);

$mydir = './mydir'; 
mkdir $mydir unless -d $mydir;

	# Dateiendung festlegen
$suffix = '.tmp';

$dir = tempdir( DIR => $mydir, CLEANUP =>  0 );

($fh, $filename) = tempfile( DIR => $dir,
                             SUFFIX => $suffix,
                           );

print "Verzeichnis: $dir\n";
print "Datei:       $filename\n";

exit();

Das Programm erzeugt folgende Ausgabe:

Verzeichnis: mydir/SmAZ7Dj9AO
Datei:       mydir/SmAZ7Dj9AO/eyi7h7fT0l.tmp

Beispiel 4: Länge des Dateinamens festlegen

File::Temp legt automatisch zufällige Dateinamen der Länge 10 an. Die Länge des Dateinames lässt sich durch Übergabe eines Templates als ersten Parameter an tempfile() ändern. Der Großbuchstabe X wird als Platzhalter für zufällige, von File::Temp erzeugte Buchstaben, Ziffern und Sonderzeichen verwendet.

#!/usr/bin/perl
use warnings;
use strict;

use File::Temp qw/ tempfile tempdir /;

my ($dir, $mydir, $fh, $filename, $suffix, $template);

$mydir = './mydir'; 
mkdir $mydir unless -d $mydir;

	# Dateiendung festlegen
$suffix = '.tmp';

# Dateinamen anpassen
# 12 zufällige Elemente (X)

$template = 'tmp_XXXXXXXXXXX';

$dir = tempdir( DIR => $mydir, CLEANUP =>  1 );

($fh, $filename) = tempfile($template,
                             DIR => $dir,
                             SUFFIX => $suffix,
                           );

print "Verzeichnis: $dir\n";
print "Datei:       $filename\n";

exit();

Das Programm erzeugt folgende Ausgabe:

Verzeichnis: mydir/73vWvvqRno
Datei:       mydir/73vWvvqRno/tmp_qzbFzrot_fe.tmp

Beispiel 5: Objektorientierung

File::Temp bietet neben der bereits gezeigten prozeduralen auch eine objektorientierte Schnittstelle an.

Das oben gezeigte Beispiel 4 lässt sich wie folgt auch objektorientiert schreiben.

#!/usr/bin/perl
use warnings;
use strict;

use File::Temp;

my ($dir, $mydir, $fh, $filename, $suffix, $template);

$mydir = './mydir'; 
mkdir $mydir unless -d $mydir;


# Temp-Verzeichnis unterhalb von $mydir erzeugen 
$dir = File::Temp->newdir( DIR     => $mydir,
                           CLEANUP => 1,
                         );

	# Dateiendung festlegen
$suffix = '.tmp';
# Dateinamen anpassen
# 12 zufällige Elemente (X)

$template = 'tmp_XXXXXXXXXXX';


$fh = File::Temp->new( TEMPLATE => $template,
                        DIR      => $dir,
                        SUFFIX   => $suffix,
                      );

print "Verzeichnis: ", $dir->dirname(),  "\n";
print "Datei:       ", $fh->filename(), "\n";

exit();

Ausgabe wie in Beispiel 4.

Siehe auch

Weitere Posts