Sehr Umfangreiche Webseite zum Programmieren in C Perl CGI, Skripting, Konvertieren, int ceil sprintf hex oct floor Runden AbschneidenPerl Kurs Skripting Datei Ein/Ausgabe Verzeichnis open read write STDOUT STDIN print sysopen sysread syswrite Datei Ein/Ausgabe Verzeichnis open read write STDOUT STDIN print sysopen sysread syswrite Perl Kurs Kapitel 13

13.10. Verzeichnisse : opendir, readdir und closedir           zurück Ein Kapitel tiefer zum Inhaltsverzeichnis

Mit den Funktionen opendir, readdir und closedir haben Sie die Möglichkeit Dateiverzeichnisse, Eintrag für Eintrag durchzulaufen.

Mit opendir können Sie ein Verzeichnis, wie eine normale Datei, öffnen. Ebenso wie bei einer normalen Datei haben Sie als ersten Parameter ein Handle, das Directory-Handle. Dies ist genauso einzusetzen wie schon das File-Handle. Als zweiten Parameter benötigen Sie die Pfadangabe, die Sie öffnen wollen. Wird keine Pfadangabe gemacht gilt das aktuelle Verzeichnis. Im Fehlerfall liefert opendir undef zurück. Auch hier steht der Fehler in der reservierten Fehler-Variablen $! Hier der Syntax zu opendir ...

opendir(Directoryhandle, Pfad) or die $!;

Um nun ein Beispiel dafür zu zeigen, benötigen Sie noch die Kenntnis zu einer Funktion mit der Sie dieses Verzeichnis auslesen können, nämlich readdir. Mit readdir können Sie nun, bei Erfolgreichen öffnen mit opendir vorausgesetzt, das Verzeichnis auslesen. Hierzu der Syntax zu readdir ...

while( defined ($name=readdir(Directoryhandle))){ .... }

Mit closedir geben Sie das nicht mehr benötigte Directory-Handle frei. Der Syntax zu closedir lautet  ...

closedir Directoryhandle;

Hierzu ein Skript, womit das aktuelle Verzeichnis ausgelesen wird ...

#!/usr/bin/perl -w

opendir(DH, ".") or die "Fehler bei opendir : $!\n";
while(defined($name=readdir(DH))){
   print $name , "\n";
   }
closedir DH;

Wenn Sie nun z.B. nach Textdateien in Ihrem Verzeichnis suchen, brauchen Sie nur den Pattern-Matching-Operator verwenden ...

#!/usr/bin/perl -w

opendir(DH, ".") or die "Fehler bei opendir : $!\n";
while(defined($_=readdir(DH))){
   print $_ , "\n" if $_=~m/.*\.txt/;
   }
closedir DH;

Wenn Sie nur Verzeichnisse Auslesen wollen, brauchen Sie nur den Schalter -d (Directory) verwenden ...

#!/usr/bin/perl -w

opendir(DH, ".") or die "Fehler bei opendir : $!\n";
while(defined($_=readdir(DH))){
   print $_ , "\n" if -d;
   }
closedir DH;

Mehr zu den Dateioperatoren, wie hier mit -d, erfahren Sie später.

13.11. Verzeichnisse erstellen und löschen           zurück Ein Kapitel tiefer Ein Kapitel höher zum Inhaltsverzeichnis

Ein Verzeichnis zu erstellen ist recht einfach. Dafür benötigen Sie lediglich die Funktion mkdir. Als Parameter für mkdir übergeben Sie, den Verzeichnisnamen mit, wenn es nicht im aktuellen Verzeichnis angelegt werden soll, Pfadangabe. Als zweiten Parameter übergeben Sie die Zugriffsrechte auf dieses Verzeichnis ...

mkdir("newdir", 0700) or warn $!;

Mit der Funktion rmdir können Sie ein leeres Verzeichnis (nur bei Linux/Unix), es sind nur noch '.' und '..' in diesem Verzeichnis, löschen ...

rmdir("newdir") or warn $!;

Da man mit rmdir nur eine leeres Verzeichnis löschen kann, steht man vor dem Problem, wie man den Inhalt diese Verzeichnisses löschen kann. In einer Konsole bei Linux könnten Sie folgt vorgehen  ...

rm -rf newdir

Also könnten Sie dies unter Perl ebenso verwenden ...

system("rm -rf $verzeichnis") == 0 or warn "Fehler";

Unter Unix/Linux mag das funktionieren, aber da es Perl auch noch auf anderen Systemen gibt empfiehlt es sich das Standardmodul File::Path anzusehen. Hier nun das Beispiel ...

#!/usr/bin/perl -w

use File::Path;

mkdir("mydir", 0700)
      or die "Fehler bei mkdir.... $!\n";
system("touch ./mydir/a1.txt ./mydir/a2.txt ./mydir/a3.txt") == 0
        or die $! , "\n";

#Verzeichnis auslesn
opendir(DH, "./mydir") or die "Fehler bei opendir : $!\n";
while(defined($_=readdir(DH))){
 print $_ , "\n";
 }
closedir DH;

rmdir("./mydir") or warn "Kann Verzeichnis ./mydir nicht löschen : $! \n";

print "Neuer Versuch.........\n";
rmtree("./mydir") or die "Konnte ./mydir nicht löschen\n";
print "........Erfolgreich\n";

Hier verwenden Sie die Portable Version mit dem Modul File::Path und die darin enthaltene Funktion rmtree.

13.12. Dateioperatoren und Attribute mit stat           zurück Ein Kapitel tiefer Ein Kapitel höher zum Inhaltsverzeichnis

In Perl gibt es einige Dateioperatoren, mit denen Sie Informationen verschiedenster Art zu einer Datei bekommen. Ich werde dabei nicht auf alle Eingehen. Zuerst folgende Dateitestoperatoren ...

#!/usr/bin/perl -w

$file="file.txt";

#Falls file.txt nicht existiert (-e) wird Sie erzeugt....
system("touch file.txt") if not -e $file;
#Überprüfung ob file.txt existiert.....
print "Datei file.txt exisitiert\n" if -e $file;

#Wenn Datei 0Bytes gross ist öffnen....
open(FH,">file.txt") if -z $file;
#Mit 100 Bytes füllen
print FH "x" x99 , "\n";
close FH;

print "Datei hat nicht die Länge Null\n" if not -z $file;

#Wir überprüfen die Grösse in Bytes von file.txt
print "Datei ist grösser als 100 Bytes\n" if -s $file > 100;
print "Datei ist 100 Bytes gross\n" if -s $file == 100;
#So gehts auch......
print -s $file , " Bytes\n";

#Wieder weg damit.....
unlink($file);

Das Programm erzählt die Anwendungen der Dateitestoperatoren von selbst.

#!/usr/bin/perl -w

opendir(DH, ".") or die "opendir $!\n";
while(defined($name=readdir(DH))){
   print $name , "\n" if -s $name > 1024*10;
   }
closedir DH;

Mit diesem Beispiel geben Sie zum Beispiel alle Dateien aus, die Größer als 10KB sind. Idealer lässt sich der -s Operator mit grep verwenden ...

#!/usr/bin/perl -w

@files = <*.txt>;

@number = grep { -s > 1024*10 }@files;

print "Textdateien grösser als 10KB : \n";
foreach(@number){
   print $_ , "\n";
   }

Hier werden alle Textdateien ausgegeben die größer als 10KB sind.

Um zu testen um was für eine Dateiart es sich handelt, gibt es folgende Dateitestoperatoren ...

Eingesetzt werden diese Dateioperatoren genauso wie schon oben gesehen. Auch hierzu ein Beispiel ...

#!/usr/bin/perl -w

@files = <*>;

@directory = grep { -d }@files;
@file = grep { -f }@files;

print "Alle VERZEICHNISSE : \n";
print "@directory\n\n";
print "Alle regulären DATEIEN : \n";
print "@file\n\n";

Hier kommen alle Dateiverzeichnisse in @directory und alle regulären Dateien in @file.

Wenn Sie noch mehr Informationen über eine Datei oder offenes File-Handles benötigen, können Sie auch die Funktion stat verwenden. stat liefert bei Erfolg eine Liste mit 13 Elementen zurück mit folgendem Inhalt, in der selben Reihenfolge ...

Und auch hierzu das Anwendungsbeispiel zu stat ...

#!/usr/bin/perl -w

$file="out.txt";
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
 $atime,$mtime,$ctime,$blksize,$blocks) = stat($file);

$at=scalar localtime($atime);
$mt=scalar localtime($mtime);
$ct=scalar localtime($ctime);

print "Datei : $file\n";
print "Device : ($dev, $rdev) Inode : $ino\n";
print "Mode : $mode\n";
print "Links : $nlink\n";
print "Eigentümer : ($uid, $gid)\n";
print "Grösse(logisch) : $size Bytes\n";
print "Grösse(physisch) : $blocks\n";
print "Blockgrösse : $blksize\n";
print "Letzter Zugriff : $at\n";
print "Letzte Änderung : $mt\n";
print "Inode-Änderung : $ct\n";

13.13. Dateien löschen           zurück Ein Kapitel tiefer Ein Kapitel höher zum Inhaltsverzeichnis

Um ein Datei zu löschen benötigen Sie die Funktion unlink. Mit unlink löschen Sie den Dateinamen. Beispielsweise ...

unlink($name) or die $!;

Die, in anderen Programmiersprachen, bekannten Löschfunktionen wie remove oder delete gibt es in Perl nicht. Und um genau zu sein Löschen Sie mit unlink nicht die Datei von der Festplatte, sondern es wird nur der Name aus dem Dateiverzeichnis entfernt.

Recht praktisch ist unlink auch, weil Sie damit eine ganze Liste von Dateinamen löschen können ...

unlink(@kill_all) or die $!;

Auf Unix-Systemen können Sie auch folgende Version zum löschen von Dateinamen verwenden ...

system("rm $name");
system("rm", @files);

Auf anderen Systemen, wo rm nicht vorhanden ist, wird dies Programm aber dann nicht laufen.

13.14. Dateien sperren           zurück Ein Kapitel tiefer zum Inhaltsverzeichnis

Wozu benötigen Sie Dateisperren? Wenn mehrere Prozesse auf eine Datei zugreifen und in diese Datei schreiben wollen. Zum bei CGI-Skripts wie ein Gästebuch oder ein Besucher-Counter. Zwei Besucher auf Ihrer Seite tragen sich gleichzeitig ins Gästebuch ein und wollen zur gleichen Zeit in die selbe Datei schreiben. Die Folge wäre ein Datensalat. Als Abhilfe dafür benutzt man dazu Dateisperren.

Wie kann man nun ein ganze Datei sperren? Hierzu ein simples Skriptbeispiel  ...

#!/usr/bin/perl -w

use Fcntl qw(:DEFAULT :flock);

open(FH, "<<test.txt") or die "open : $!\n";

flock(FH, LOCK_EX) or die "Fehler flock : $!\n";

#Ab hier kann kein anderer Prozess mehr auf die Datei zugreifen
print FH "Dieser Text kann nur von PID $$ geschrieben werden\n";

 flock(FH, LOCK_UN) or die "Fehler flock $!\n";
#Jetzt können wieder andere Prozesse auf test.txt zugreifen

close FH;

Die erste Frage dürfte nun lauten, was passiert wenn User1  in die Datei schreibt und 1 Sekunde darauf User2 und der Schreibvorgang von User1 war noch nicht fertig? Es passiert gar nichts. User2 wird solange blockiert bis User1 die Dateisperre wieder freigibt.

Zwei Arten von Sperren können Sie verteilen. In unserem Beispiel haben Sie mit LOCK_EX eine exklusive Sperre verwendet. Mit dieser Sperre stellen Sie sicher, das niemand anderes während dieser Zeit diese Datei lesen noch beschreiben kann.

Die zweite Möglichkeit währe eine gemeinsame Sperre (LOCK_SH). Mit dieser dieser Sperre können Sie realisieren das ein Prozess eine Exklusiv-Sperre erhält, damit der Prozess mit der Exklusiv-Sperre, die Lesenden Prozesse nicht stört. Das daher weil alle Prozesse ein Sperre erhalten haben (shared lock).

Sperren sind übrigens nicht mit Zugriffsrechte gleichzusetzen. Es sorgt immer wieder für Verwirrung, dass man trotz einer Sperre die Datei lesen kann. Die Sperre gilt nur für Prozesse die ebenfalls mit flock, versuchen darauf zurückzugreifen. Bei CGI-Skripts brauchen Sie sich somit keine Gedanken darum machen. Es sei denn, jemand weiß wo sich das zu beschriebene File befindet und Sie haben die Zugriffsrechte falsch gesetzt.