SELFHTML/Navigationshilfen Perl Perl-Funktionen | |
Funktionen für Ein-/Ausgabe und Lesen/Schreiben von Daten |
|
Allgemeines zu diesen Funktionen |
|
Zu den Grundlagen der Unix-Philosophie (Perl entstand in der Unix-Welt) gehört, dass jedem Prozess drei Standardkanäle zugeordnet werden (können). Es gibt grundsätzlich einen voreingestellten Eingabekanal STDIN
- standard input -, einen voreingestellten Ausgabekanal STDOUT
- standard output - und einen voreingestellten Kanal für Fehlermeldungen STDERR
- standard error. STDIN
ist normalerweise mit der Tastatur verbunden oder aber mit einem anderen Gerät, beispielsweise einer Netzwerkschnittstelle, STDOUT
und STDERR
mit dem Terminal, also beispielsweise dem Monitor. Solange man nur etwas hineinschreibt oder daraus liest, verhalten sich diese Standardkanäle wie normale Dateien. Der große Vorteil besteht darin, dass die von ihnen übermittelten oder gespeicherten Daten umgelenkt werden können, so dass die Ausgabe von STDOUT
auf dem Bildschirm erscheinen und der Inhalt von STDERR
gleichzeitig in eine Protokolldatei (log) geschrieben werden kann. Ob diese Kanäle einer Software zur Verfügung stehen, ist davon abhängig, ob die Software-Entwickler sie vorgesehen haben.
Für Perl gibt es alle drei Standardkanäle. Ein Perl-Script kann also von STDIN
Daten lesen und auf STDOUT
Daten ausgeben. Bei Verwendung eines Webservers mit CGI-Schnittstelle werden die Daten aus STDOUT
nun in eine spezielle Datei umgeleitet, die vom Webserver an den Web-Browser weitergegeben wird. Dasselbe geschieht mit den Daten, die der Webserver gemeinsam mit einer Browser-Anfrage erhält - der Webserver leitet sie in seinen Ausgabekanal STDOUT
, womit diese Daten (z.B. Formulardaten) dem über ein CGI-Script aufgerufenen Perl-Interpreter bereitgestellt werden können.
Die drei Kanäle stellen für Perl so genannte Handles dar. Neben diesen Standardkanälen zur Ein- und Ausgabe können Sie als Programmierer eigene Kanäle zur Ein- und Ausgabe öffnen. Dabei vergeben Sie auch eigene Namen für die Handles. Das ist zum Beispiel erforderlich, wenn Sie Daten statt von der Tastatureingabe aus einer Datei lesen oder statt auf den Bildschirm in eine Datei schreiben wollen. Um eine Datei lesen oder schreiben zu können, erzeugen Sie also einfach ein Datei-Handle. Dies passiert beim Öffnen einer Datei - hierzu dient vor allem die Funktion open. Nachdem Sie eine Datei geöffnet und dabei ein Datei-Handle vergeben haben, haben Sie über das Datei-Handle Zugriff auf die Datei.
Perl stellt diverse Funktionen zur Verfügung, um auf Dateien lesend und schreibend zugreifen zu können. Zu einem Datei-Handle gehört ferner ein Dateizeiger. Der Dateizeiger speichert beim Lesen und Schreiben die aktuelle Byteposition innerhalb der Datei. Sie können die Position des Dateizeigers ermitteln und den Dateizeiger zum Beispiel bei Dateien mit bestimmten Dateiformaten an eine andere Position setzen. Auf diese Weise können Sie Schreib- und Lesevorgänge genau steuern.
Für Verzeichnisse - Ordner eines Dateisystems - gibt es eigene Funktionen. Ein Verzeichnis können Sie ebenfalls öffnen. Dann können Sie Einträge des Verzeichnisses lesen, zum Beispiel, um zu ermitteln, ob in dem Verzeichnis Dateien eines bestimmten Typs vorkommen. Verzeichnisfunktionen erkennen Sie an dem dir
im Namen. So sind etwa open
oder seek
Dateifunktionen, während opendir
und seekdir
Verzeichnisfunktionen sind.
Neben den normalen Funktionen zum Lesen und Schreiben von Dateien gibt es auch systemnahe Varianten der entsprechenden Funktionen. Benutzen Sie solche Funktionen jedoch nur, wenn Sie einen besonderen Grund dazu haben! Diese Art von Funktionen erkennen Sie am sys
im Namen. Während beispielsweise read
eine normale Lesefunktion ist, ist sysread
die entsprechende systemnahe Variante dieser Funktion.
Perl-Scripts, die Sie als CGI-Scripts einsetzen, können mit Hilfe dieser Funktionen Dateien auf dem Server-Rechner lesen und schreiben. Auf das Dateisystem eines entfernten Client-Rechners, dessen dort laufender Web-Browser vom Webserver Daten angefordert hat, haben Sie mit diesen Funktionen keinen Zugriff!
Wichtig, um Binärdateien (z.B. Grafikdateien) korrekt einzulesen oder zurückzuschreiben, wenn das Betriebssystem, unter dem das Perl-Script läuft, zwischen Text- und Binärdateien unterscheidet. Unix macht diese Unterscheidung nicht, die Funktion binmode
ist deshalb für Perl-Scripts unter Unix bedeutungslos. MS-Windows dagegen unterscheidet zwischen Text- und Binärmodus.
Bei nicht binären Dateien, also bei Klartextdateien, werden die zwei aufeinander folgenden Steuerzeichen CR (Carriage Return) und LF (Line Feed) beim Lesen der Datei unter Betriebssystemen wie DOS/Windows automatisch zu einem LF zusammengefasst. Beim Schreiben einer Textdatei wird jedes LF automatisch wieder in zwei Zeichen CR und LF umgewandelt.
Durch Aufruf der Funktion binmode
schalten Sie diesen Automatismus aus. So verhindern Sie, dass der Automatismus an Stellen greift, an denen er nicht greifen soll, etwa, wenn Sie numerisch gespeicherte Daten einlesen, die zufällig zwei Bytes in Folge enthalten können, deren Werte den Zeichenwerten für CR und LF entsprechen.
Erwartet als Parameter:
1. das Handle eines Ein-/Ausgabekanals.
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); my $AnzahlBytes = -s "/usr/web/src/ship.gif"; my $Speicher; open(GRAFIK, "</usr/web/src/ship.gif"); binmode(GRAFIK); my $geleseneBytes = read(GRAFIK, $Speicher, $AnzahlBytes); close(GRAFIK); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title></head><body>\n"; print "<h1>der Inhalt der Grafikdatei als Zeichensalat:</h1>\n"; print "<p><tt>$Speicher</tt></p>"; print "</body></html>\n";
Das Beispiel liest eine GIF-Grafikdatei binär ein. Dazu wird die Datei mit open geöffnet. Anschließend wird die Funktion binmode
mit dem Datei-Handle der geöffneten Datei (GRAFIK
) aufgerufen. Danach wird die Datei mit der Funktion read eingelesen.
Zu Testzwecken wird HTML-Code, der den eingelesenen Inhalt der Grafik als Zeichensalat darstellt, wieder ausgegeben. Der eingelesene Inhalt befindet sich nach dem Einlesen im Skalar $Speicher
.
Weitere Einzelheiten zum Einlesen binärer Dateien werden bei der Funktion read beschrieben.
Der verwendete Ausdruck -s
zum Feststellen der Dateigröße, gespeichert in $AnzahlBytes
, gehört zu einer Reihe ähnlicher Ausdrücke, die das Ermitteln von Eigenschaften einer Datei erlauben. Weitere Einzelheiten dazu im Abschnitt über Dateitestoperatoren.
Schließt eine Datei, die zuvor mit open geöffnet wurde.
Erwartet als Parameter:
1. das Handle eines geöffneten Ein-/Ausgabekanals, der geschlossen werden soll.
Ein vollständiges Beispiel mit Erläuterung der beiden zusammenhängenden Funktionen open
und close
wird bei der Funktion open behandelt.
Wenn Sie eine zuvor geöffnete Datei nicht explizit mit close
schließen, wird die Datei von Perl beim Beenden des Scripts automatisch geschlossen.
Schließt ein Verzeichnishandle, das zuvor mit opendir geöffnet wurde.
Erwartet als Parameter:
1. das Verzeichnishandle.
Ein vollständiges Beispiel mit Erläuterung der drei zusammenhängenden Funktionen opendir
, readdir
und closedir
wird bei der Funktion opendir behandelt.
Fragt eine geöffnete Datei daraufhin ab, ob der Dateizeiger das Dateiende erreicht hat.
Erwartet als Parameter:
1. das Handle des Ein-/Ausgabekanals.
Gibt true
zurück, wenn das Dateiende erreicht ist, und false
, wenn es nicht erreicht ist.
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); my $max = 100000; my $i = 0; my $Status = 0; print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title>\n"; print "</head><body>\n"; open(DATEI, "</usr/chatlog/lastnight.txt"); while(1) { if(eof(DATEI)) { $Status = 1; last; } if($i > $max) { $Status = 2; last; } getc(DATEI); $i++; } close(DATEI); if($Status == 1) { print "<p>Datei war kleiner als $max Bytes, daher ganz gelesen</p>\n"; } if($Status == 2) { print "<p>Datei war zu groß, daher nur $max Bytes gelesen</p>\n"; } print "</body></html>\n";
Das Beispiel erzeugt HTML-Code. Dabei wird mit der Funktion open eine Textdatei /usr/chatlog/lastnight.txt
geöffnet. Die geöffnete Datei wird in einer while-Schleife mit der Funktion getc Zeichen für Zeichen eingelesen. Da die Schleifenbedingung (1)
immer wahr ist, werden innerhalb der Schleife Abbruchbedingungen formuliert. Wenn das Dateiende erreicht ist - if(eof(DATEI))
- wird der Skalar $Status
auf 1 gesetzt und die Schleife durch last
beendet.
Die Schleife wird aber auch dann beendet, wenn mehr Zeichen eingelesen wurden, als in $max
definiert sind. In diesem Fall wird $Status
auf 2 gesetzt.
Durch Abfragen des Wertes von $Status
kann nach Beenden der Schleife festgestellt werden, was die Schleife zum Abbruch gebracht hat. Abhängig davon wird ein entsprechender Satz ausgegeben.
if(eof(DATEI))
("wenn Dateiende erreicht") oder while(! eof(DATEI))
("solange Dateiende nicht erreicht") sind typische Formulierungen beim Einsatz der Funktion eof
. Sinnvoll sind solche Abfragen und Schleifenbedingungen vor allem dann, wenn Sie Dateien zeichenweise (mit der Funktion getc
) oder blockweise (mit der Funktion read) einlesen.
Jeder geöffnete Ein-/Ausgabekanal hat intern eine Nummer, auch die nicht selbst geöffneten Ausgabekanäle STDIN
, STDOUT
und STDERR
. Mit dieser Funktion können Sie die interne Nummer eines Ein-/Ausgabekanals ermitteln.
Erwartet als Parameter:
1. das Handle eines Ein-/Ausgabekanals.
Gibt die interne Nummer des Ein-/Ausgabekanals zurück.
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title>\n"; print "</head><body>\n"; open(DATEI, "</usr/texte/wichtig.txt"); my $Datei = fileno(DATEI); close(DATEI); my $Eingabe = fileno(STDIN); my $Ausgabe = fileno(STDOUT); my $Fehler = fileno(STDERR); print "Eingabe= $Eingabe, Ausgabe = $Ausgabe, Fehler = $Fehler, Datei = $Datei\n"; print "</body></html>\n";
Das Beispiel erzeugt HTML-Code für den aufrufenden Browser. Dabei wird mit der Funktion open eine Textdatei /usr/texte/wichtig.txt
geöffnet. Mit fileno(DATEI)
wird die interne Nummer des Handles dieser Datei ermittelt und in einem Skalar $Datei
gespeichert. Ebenso werden die internen Nummern der drei Standardkanäle ermittelt und in entsprechenden Skalaren gespeichert. Schließlich gibt das Script die ermittelten Nummern aus.
Regelt, wie andere Prozesse auf eine Datei zugreifen können, während der aktuelle Prozess die Datei geöffnet hält. Bei CGI-Scripts kann dies sehr wichtig sein. Denn während ein vom Browser eines Anwenders aufgerufenes Script seine Arbeit verrichtet, kann ja bereits ein weiterer Browser eines anderen Anwenders das selbe Script aufrufen. Die beiden Prozesse arbeiten dann im Arbeitsspeicher des Server-Rechners zwar unabhängig voneinander, führen aber nun mal den gleichen Code aus und greifen auf die gleichen Dateien zu. Damit nicht ein anderer Prozess Daten löscht, die der aktuelle Prozess gerade geschrieben hat, ist es dem Prozess zum Beispiel möglich, die Datei vor Zugriffen zu schützen.
Wichtig: Bei Betriebssystemen, die intern kein flock
implementiert haben, führt die Anwendung dieser Funktion zu einem Fehler, so etwa auch bei Windows 95/98.
Erwartet als Parameter:
1. das Handle der geöffneten Datei.
2. die Nummer einer Sperroption oder eine Konstante - erlaubt sind die Nummern 1
, 2
, 4
und 8
oder die Konstanten LOCK_SH
, LOCK_EX
, LOCK_NB
und LOCK_UN
.
1
oder Konstante LOCK_SH
bedeutet shared (Datei mit anderen Prozessen teilen, zum Beispiel, wenn ein Prozess, der lesend auf eine Datei zugreift, andere Prozesse nicht stören soll, die gleichzeitig diese Datei lesen),2
oder Konstante LOCK_EX
bedeutet exclusive (keinem anderen Prozess irgendeinen Zugriff auf die Datei erlauben),8
oder Konstante LOCK_UN
bedeutet unlock (Zugriffsschutz ausdrücklich wieder aufheben).4
oder Konstante LOCK_NB
bedeutet non-blocking (nur in Verbindung mit 1
oder 2
bzw. LOCK_SH
oder LOCK_EX
erlaubt und beendet den Zugriffsversuch auf die Datei sofort statt zu warten, bis ein Zugriff möglich ist).Die Konstanten können Sie nur verwenden, wenn Sie das Modul Fcntl
einbinden (siehe Beispiel weiter unten).
Gibt true
zurück, wenn der Vorgang erfolgreich war, und false
, wenn er nicht erfolgreich war.
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); use Fcntl ':flock'; $| = 1; open(DATENDATEI, "</db/daten.csv"); flock(DATENDATEI, LOCK_EX); # angenommen, hier passiert etwas Zeitaufwändiges, # und derweil versucht ein anderer Prozess auf die gleiche Datei zuzugreifen # dann greift die Sperre flock(DATENDATEI, LOCK_UN); close(DATENDATEI);
Wenn Sie anstelle der Nummern lieber die Konstanten verwenden möchten, müssen Sie zuerst einen Befehl zum Einbinden des Sperrmoduls notieren, etwa in der obigen Form:
use Fcntl ':flock';
Nachdem Sie eine Datei erfolgreich geöffnet und ein entsprechendes Datei-Handle für den Zugriff auf die Datei haben, können Sie die Sperroptionen für die Datei festlegen. Im Beispiel geschieht das nach dem Aufruf der open-Funktion mit Hilfe der Anweisung flock(DATENDATEI, LOCK_EX);
Dabei ist DATENDATEI
das Datei-Handle, und LOCK_EX
die Angabe zur gewünschten Sperroption. Im Beispiel wird die Datei exklusiv gesperrt. Solange die Sperre innerhalb des Scripts nicht aufgehoben oder die Datei geschlossen wird, kann kein anderer Prozess, der flock
beachtet, gleichzeitig in die Datei schreiben.
Die beiden Befehle
flock(DATENDATEI, LOCK_UN);
close(DATENDATEI);
dienen im obigen Beispiel nur zum besseren Verständnis. Das explizite Beenden der Sperre ist eigentlich überflüssig, wenn es erst beim Schließen der Datei mit der close-Funktion erfolgen soll. Denn close
hebt zugleich jede Angabe zur Dateisperre auf.
Die Anweisung $| = 1;
im obigen Beispiel dient zum Ausschalten der gepufferten Ausgabe (vgl. dazu vordefinierte Variablen in Perl). Dies ist beim Sperren von Dateien zu empfehlen. Denn andernfalls kann es passieren, dass durch gepufferte und verzögerte Ausgabe das Schreiben von Daten erst dann stattfindet, wenn die Sperre bereits aufgehoben ist. Dies würde den ganzen Zweck der Sperre überflüssig machen.
Wenn Sie mit der Sperroption 4
bzw. LOCK_NB
arbeiten möchten, müssen Sie diese Option durch eine bitweise Oder-Verknüpfung mit einer Option zum Sperren verknüpfen. Beispiele:
flock(DATENDATEI, LOCK_EX | LOCK_NB);
flock(DATENDATEI, LOCK_SH | LOCK_NB);
Wichtig: flock
erzwingt keine Sperre, sondern hat nur empfehlenden Charakter. Der Zugriffsschutz ist nur dann wirksam, wenn alle Prozesse, die auf die Datei zugreifen, flock
beachten.
Dies ist eine mächtige Funktion, um Daten vor der Ausgabe an einem zeichenorientierten Ausgabegerät wie Textbildschirm oder Zeilendrucker ansprechend zu formatieren. Im Zusammenhang mit CGI-Scripts findet diese Funktion kaum Verwendung, da die wenigsten Web-Browser zeichenorientiert arbeiten.
#!/usr/bin/perl -w use strict; my $Zuname = "Hummel"; my $Vorname = "Hilde"; my $Wohnort = "Hammelbach"; format STDOUT = @<<<<<<<<<<<<< @<<<<<<<<<<<<< aus @<<<<<<<<<<<<< $Vorname, $Zuname, $Wohnort . write;
In Beispiel 1 wird folgendes ausgegeben:
Hilde Hummel aus Hammelbach
Die Formatierung der Ausgabe geschieht durch das format
-Konstrukt. Die eigentliche Ausgabe geschieht durch den anschließenden Befehl write
.
Bei dem Konstrukt zur Formatierung geben Sie hinter format
einen Namen für das Format an, normalerweise den Namen des gewünschten Datei-Handles. Der Name ist jedoch in Wirklichkeit kein Datei-Handle, er sieht nur so aus. Das Default-Format für ein Datei-Handle hat lediglich den gleichen Namen wie das Datei-Handle. Im obigen Beispiel wird der Formatname STDOUT
angegeben, weil auf die Standardausgabe STDOUT
geschrieben werden soll. Hinter dem Formatnamen folgt ein Gleichheitszeichen.
Die Zeilen, die danach folgen, bestehen immer aus Zeilenpaaren. Zuerst werden eine oder mehrere Formatierzeile(n) notiert, und anschließend eine Argumentzeile. In der Formatierzeile definieren Sie mit Hilfe spezieller Zeichensymbole das Ausgabeformat für bestimmte Felder, und in der Argumentzeile nennen Sie die Variablen, die in den entsprechenden Feldern darüber ausgegeben werden.
Mit einem Punkt (.) in einer eigenen Zeile wird das Format-Konstrukt beendet.
Für die Formatierzeile gibt es folgende Regeln:
Anweisung | Bedeutung |
---|---|
@<<<<<<< |
Feld linksbündig ausrichten. Die Anzahl der < -Zeichen bestimmt die Feldbreite in Zeichen. Längere Inhalte werden bei der Ausgabe links abgeschnitten.
|
@>>>>>>> |
Feld rechtsbündig ausrichten. Die Anzahl der > -Zeichen bestimmt die Feldbreite in Zeichen. Längere Inhalte werden bei der Ausgabe rechts abgeschnitten.
|
@|||||| |
Feld zentriert ausrichten. Die Anzahl der | -Zeichen bestimmt die Feldbreite in Zeichen. Längere Inhalte werden bei der Ausgabe rechts abgeschnitten.
|
@#.## |
Feld als Zahl mit Dezimalzeichen formatieren. Als Dezimalzeichen ist nur der Punkt erlaubt. Die Anzahl der # -Zeichen vor dem Punkt bestimmt die Vorkomma-Feldbreite, kleinere Zahlen werden dabei rechts zum Dezimalzeichen hin ausgerichtet. Die Anzahl der # -Zeichen hinter dem Punkt bestimmt die Nachkomma-Feldbreite. Bei weniger Nachkommaziffern als angegebenen Zeichen werden Nullen angehängt.
|
Zusätzlich zu diesen Formatiermöglichkeiten gibt es einige vordefinierte Variablen, die Sie für die Ausgabe benutzen können.
#!/usr/bin/perl -w use strict; format STDOUT = Seite @<< @>>>>>>> $%, $~ . write;
In Beispiel 2 wird folgendes ausgegeben:
Seite 0 STDOUT
Die Formatierung der Ausgabe geschieht durch ein format
-Konstrukt. Anstelle gewöhnlicher Variablen werden jedoch spezielle vordefinierte Variablen ausgegeben. Folgende spezielle Variablen sind möglich:
Anweisung | Bedeutung |
---|---|
$% |
aktuelle Seitennummer |
$= |
Anzahl Zeilen pro Seite |
$- |
Anzahl übrig gebliebener Zeilen auf der aktuellen Seite |
$~ |
Name des aktuellen Formats - per Voreinstellung der Name des benutzten Datei-Handles. |
$^ |
Name des aktuellen Kopfseitenformats - per Voreinstellung der Name aktuellen Formats plus der Zeichenfolge _TOP . |
$: |
Trennzeichen(folge) bei mehrzeiligen Einträgen. |
$^L |
Trennzeichen(folge) für Seitentrenner. |
Für längere Ausgaben, zum Beispiel von Dateien, können Sie auch Kopfzeilen benutzen. Das folgende Beispiel zeigt, wie Sie eine Datei ausgeben können:
#!/usr/bin/perl -w use strict; use vars qw($Zeile); open(DATEI,"</usr/texte/daten.txt"); format STDOUT_TOP = **************************************************** Seite @>> $% **************************************************** . format STDOUT = @<<<<<<<<<<<<<<< $Zeile; . while(<DATEI>) { chomp $_; $Zeile = $_; write; } close(DATEI);
In Beispiel 3 werden von einer angenommenen Textdatei von jeder Zeile die ersten 15 Zeichen ausgegeben.
Die Formatierung der Ausgabe in Beispiel 3 geschieht durch zwei format
-Konstrukte. Die beiden Konstrukte erhalten die Namen STDOUT_TOP
und STDOUT
. Durch die Zeichenfolge _TOP
am Ende eines Formatnamens teilen Sie Perl mit, dass es sich um eine Kopfzeilendefinition handelt. Im Beispiel wird die Kopfzeile mit zwei aus Sternchen bestehenden Linien und die dazwischenstehende aktuelle Seitenzahl formatiert.
Im weiteren Verlauf von Beispiel 3 sehen Sie, wie die Datei in einer while-Schleife zeilenweise in eine Variable namens $Zeile
eingelesen wird. Diese Variable wird - ebenfalls in der Schleife - jeweils ausgegeben. Für die Formatierung der Ausgabe ist das Format-Konstrukt mit dem Namen STDOUT
verantwortlich. Dort wird die Variable $Zeile
in der gewünschten Form ausgegeben.
Die Variable $Zeile
muss im obigen Beispiel global deklariert werden. Daher die Anweisung use vars qw($Zeile);
zu Beginn.
Liest ein Zeichen aus einer zuvor geöffneten Datei und positioniert den Dateizeiger um ein Zeichen weiter.
Erwartet als Parameter:
1. das Datei-Handle.
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title>\n"; print "</head><body><pre>\n"; open(DATEI, "</usr/texte/wichtig.txt"); my $Bytes = 0; while(! eof(DATEI)) { my $Zeichen = getc(DATEI); print "$Zeichen"; $Bytes++; } close(DATEI); print "</pre><b>$Bytes Zeichen gelesen!</b>\n"; print "</body></html>\n";
Das Beispiel erzeugt HTML-Code für den aufrufenden Web-Browser. Dabei wird auch mit der Funktion open eine Textdatei /usr/texte/wichtig.txt
geöffnet. Die geöffnete Datei wird in einer while-Schleife Zeichen für Zeichen eingelesen, bis das Dateiende, das mit der Funktion eof abgefragt wird, erreicht ist. Die eingelesenen Zeichen werden ausgegeben. Außerdem wird der Skalar $Bytes
bei jedem eingelesenen Zeichen um 1 erhöht. Auf diese Weise wird nebenbei die Anzahl der eingelesenen Zeichen ermittelt. Am Ende wird diese Anzahl auch mit ausgegeben.
Öffnet eine Datei zum Lesen und/oder Schreiben oder auch zum Ausführen. Auch Binärdateien werden mit dieser Funktion geöffnet.
Erwartet als Parameter:
1. den Namen des Datei-Handles (frei wählbar), und
2. den Pfadnamen der zu öffnenden Datei, entweder als absolute Pfadangabe, oder als relative Pfadangabe aus Sicht des aktuellen Verzeichnisses (wenn das aktuelle Verzeichnis unbekannt ist, empfiehlt es sich, mit Hilfe der Funktion chdir in ein bestimmtes Verzeichnis zu wechseln). Als Trennzeichen für Verzeichnispfade können Sie den einfachen Schrägstrich verwenden, auch wenn das Script auf einem Windows/DOS-Rechner laufen soll. Perl setzt diese Syntax je nach Installationsumgebung intern um.
Für den Pfadnamen der zu öffnenden Datei können Sie auch Variablen einsetzen, URIs dürfen Sie jedoch nicht angeben!
Unmittelbar vor dem (Pfad)namen der zu öffnenden Datei notieren Sie mit Hilfe der Zeichen <
, >
oder |
außerdem, wie die Datei geöffnet werden soll. Wenn Sie keine dieser Angaben machen, wird die Datei nur zum Lesen geöffnet. Folgende Angaben sind erlaubt:
<datei.dat
bedeutet: Datei datei.dat
nur zum Lesen öffnen. Die Datei muss existieren, ansonsten gibt es einen Fehler.
>datei.dat
bedeutet: Datei datei.dat
zum Schreiben von Daten öffnen. Wenn die Datei bereits existiert, wird ihr bisheriger Inhalt überschrieben. Wenn die Datei noch nicht existiert, wird sie automatisch angelegt.
>>datei.dat
bedeutet: Datei datei.dat
zum Schreiben von Daten öffnen. Wenn die Datei bereits existiert, wird der neue Inhalt an den alten Inhalt angehängt, d.h. der alte Inhalt wird nicht gelöscht. Wenn die Datei noch nicht existiert, wird sie automatisch angelegt.
+<datei.dat
bedeutet: Datei datei.dat
zum Lesen und zum Schreiben von Daten öffnen. Die Datei muss existieren, ansonsten gibt es einen Fehler.
+>datei.dat
bedeutet: Datei datei.dat
zum Lesen und zum Schreiben von Daten öffnen. Wenn die Datei bereits existiert, wird ihr bisheriger Inhalt überschrieben. Wenn die Datei noch nicht existiert, wird sie automatisch angelegt.
+>>datei.dat
bedeutet: Datei datei.dat
zum Lesen und zum Schreiben von Daten öffnen. Wenn die Datei bereits existiert, wird der neue Inhalt an den alten Inhalt angehängt, d.h. der alte Inhalt wird nicht gelöscht. Wenn die Datei noch nicht existiert, wird sie automatisch angelegt.
|datei
bedeutet: Datei datei
ist eine ausführbare Programmdatei oder ein Shell-Befehl. Das Programm bzw. der Befehl werden ausgeführt. Aus Unix-Sicht wird dabei eine Pipe zu dem Programm bzw. Befehl geöffnet.
datei|
bedeutet: Datei datei
ist eine ausführbare Programmdatei oder ein Shell-Befehl. Das Programm bzw. der Befehl werden ausgeführt. Aus Unix-Sicht wird dabei eine Pipe von dem Programm bzw. dem Befehl geöffnet.
Wenn die Datei geöffnet werden kann, gibt die Funktion open
den Wert true
zurück, andernfalls den Wert undef
.
#!/usr/bin/perl -w use strict; open(DATEI, "</tmp/server.cfg") || die "Datei nicht gefunden"; my @Zeilen = <DATEI>; close(DATEI); my @NeueZeilen; foreach(@Zeilen) { $_ =~ s/#.*//; push(@NeueZeilen,$_) if $_ !~ /^\s*\n/; } open(DATEI, ">/tmp/server.cfg") || die "Datei nicht gefunden"; print DATEI @NeueZeilen; close(DATEI);
Das Beispiel zeigt, wie Sie eine Datei öffnen, einlesen und schließen, dann wieder öffnen und den inzwischen verarbeiteten Datenbestand in die Datei zurückschreiben. Es handelt sich um eine angenommene Konfigurationsdatei, in der viele Zeilen hinter dem eigentlichen Konfigurationsbefehl Kommentare enthalten, die mit #
beginnen. Im Beispiel wird die Datei so verarbeitet, dass alle diese Kommentarzeilen gelöscht werden.
Zunächst wird die open
-Funktion aufgerufen. Dabei wird die gewünschte Datei zum Lesen geöffnet. Die Datei wird dann in den Array @Zeilen
eingelesen (in jedem Eintrag von @Zeilen
steht anschließend je eine Zeile der Datei). Nach dem Einlesen wird die Datei mit close wieder geschlossen.
Diese drei Befehle zum Öffnen, Einlesen und Schließen sind typisch.
Im obigen Beispiel werden die eingelesenen Zeilen anschließend der Reihe nach in einer foreach-Schleife verarbeitet. Dabei wird in jeder Zeile der Kommentarteil entfernt. Dies geschieht mit Hilfe eines regulären Ausdrucks zum Suchen/Ersetzen (s/#.*//g
). Dann wird die aktuell verarbeitete Zeile mit push dem Array @NeueZeilen
hinzugefügt - aber nur dann, wenn die Zeile aus etwas anderem besteht als nur aus Leerraumzeichen mit abschließendem Newline-Zeichen. Auch dazu wird wieder ein geeigneter regulärer Ausdruck angewendet.
Schließlich wird die Datei wieder geöffnet, diesmal jedoch zum Schreiben, genauer gesagt: zum Überschreiben des bisherigen Inhalts. Mit Hilfe der print-Funktion wird der Array @NeueZeilen
in die Datei geschrieben. Anschließend wird die Datei geschlossen.
Wenn Fehler beim Öffnen von wichtigen Dateien passieren, ist es meistens sinnvoll, das Script sofort zu beenden. Dazu dient die Funktion die, die auch im obigen Beispiel zum Einsatz kommt.
In den meisten Fällen ist es sinnvoll, eine geöffnete Datei sofort wieder zu schließen, sobald Sie sie nicht mehr zum Lesen oder Schreiben brauchen. Dadurch geben Sie Betriebssystem-Ressourcen frei, und andere Programme oder Prozesse können ebenfalls wieder auf die Datei zugreifen, wenn Sie die Datei zuvor gesperrt hatten.
Öffnet ein Verzeichnis, zum Beispiel, um es auszulesen. Dabei vergeben Sie ein Verzeichnishandle, über das Sie auf das Verzeichnis zugreifen können.
Erwartet als Parameter:
1. den Namen des Verzeichnishandles (frei wählbar), und
2. den Pfadnamen des zu öffnenden Verzeichnisses, entweder als absolute Pfadangabe oder als relative Pfadangabe aus Sicht des aktuellen Verzeichnisses (wenn das aktuelle Verzeichnis unbekannt ist, empfiehlt es sich, mit Hilfe der Funktion chdir in ein bestimmtes Verzeichnis zu wechseln).
Gibt TRUE
zurück, wenn das Verzeichnis geöffnet werden konnte. Wenn ein Fehler aufgetreten ist, wird dieser in der Variablen $!
gespeichert.
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); my $Verzeichnis = "/daten/web"; opendir(DIR, $Verzeichnis) || die "$Verzeichnis: $!"; my @Eintraege = readdir(DIR); closedir(DIR); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title></head><body>\n"; foreach(@Eintraege) { print "$_<br>\n"; } print "</body></html>\n";
Im Beispiel wird in dem Skalar $Verzeichnis
der Pfad eines Verzeichnisses gespeichert ("/daten/web"
). Beachten Sie, dass die Verzeichnisse des Pfades durch einfache Schrägstriche getrennt sind, nicht durch Backslashes wie unter DOS/Windows üblich. Verwenden Sie die Syntax mit den einfachen Schrägstrichen auch dann, wenn Perl bei Ihnen unter DOS/Windows läuft. Wenn Sie in einer DOS/Windows-Umgebung ein anderes als das aktuelle Laufwerk ansprechen möchten, setzen Sie einfach den Laufwerksbuchstaben mit Doppelpunkt davor, also beispielsweise c:/temp
.
Mit der Funktion opendir
wird das Verzeichnis geöffnet. DIR
ist ein selbst vergebener Name für das Verzeichnishandle. Ferner bekommt die Funktion den Skalar übergeben, in dem das gewünschte Verzeichnis gespeichert ist. Falls das Verzeichnis nicht geöffnet werden kann, endet das Script durch Aufruf der Funktion die.
Das obige Beispiel nutzt das geöffnete Verzeichnis, um mit Hilfe der Funktion readdir den Verzeichnisinhalt in eine Liste @Eintraege
einzulesen. Anschließend wird das Verzeichnis durch Aufruf der Funktion closedir geschlossen. Das Beispiel gibt dann HTML-Code mit der Liste der Verzeichniseinträge aus.
Es werden alle Verzeichniseinträge eingelesen, also Dateinamen, aber auch Namen von Unterverzeichnissen, sowie die auf den meisten Systemen vorhandenen "symbolischen" Verzeichnisnamen mit einem Punkt (.
- steht für das aktuelle Verzeichnis) oder zwei Punkten (..
- steht für das Elternverzeichnis).
Schreibt Daten auf die Standardausgabe oder in einen geöffneten Ausgabekanal, also etwa in eine Datei. Die Daten können eine einzelne Zeichenkette oder eine Liste von Zeichenketten sein. Innerhalb solcher Zeichenketten können auch Variablen vorkommen, also einzelne Skalare, aber auch ganze Listen oder Hashes. Perl erkennt die Variablen und schreibt ihren aktuellen Wert an die entsprechende Stelle.
Diese Funktion wird in CGI-Scripts sehr oft verwendet, um HTML-Code auszugeben.
Erwartet als Parameter:
1. Datei-Handle = Optionale Angabe zum Ausgabekanal. Wenn Sie diese Angabe weglassen, wird auf die Standardausgabe STDOUT
geschrieben. Wenn Sie mit open eine Datei geöffnet haben und in diese schreiben wollen, müssen Sie das bei open
vergebene Datei-Handle angeben.
2. Daten[,Daten] = Ein oder mehrere Elemente (Zeichenketten, Zahlen usw.), die geschrieben werden sollen.
Gibt true
zurück, wenn Perl die Daten erfolgreich schreiben konnte.
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title></head><body>\n"; print "<table border=\"1\">\n","<tr><td><b>Umgebungsvariable</b></td><td><b>Aktueller Wert</b></td></tr>\n"; my $i = 0; my $Eintrag; foreach $Eintrag (%ENV) { if($i == 0) { print "<tr><td>$Eintrag</td>\n"; } else { print "<td>$Eintrag</td></tr>\n"; } if($i == 0) { $i = 1; } else { $i = 0; } } print "</table>\n","</body></html>\n";
Das Beispiel gibt alle CGI-Umgebungsvariablen des Webservers aus, und zwar sauber als HTML-Tabelle formatiert. Dazu werden die Einträge des vordefinierten Hashes %ENV
in einer
foreach-Schleife abgearbeitet und in die HTML-Tabelle geschrieben. Die entsprechenden HTML-Ausgaben werden mit Hilfe von print-Befehlen geschrieben.
Im letzten der print
-Befehle können Sie sehen, wie man mehrere Zeichenketten, durch Kommata getrennt, hintereinander notieren kann.
In den print
-Befehlen innerhalb der Schleife können Sie sehen, wie eine Variable (im Beispiel der Skalar $Eintrag
) innerhalb einer auszugebenden Zeichenkette notiert ist. An der entsprechenden Stelle wird dann der jeweils aktuelle Wert von $Eintrag
ausgegeben.
Wenn Sie viele print
-Befehle hintereinander notieren müssen, können Sie auch zu einer für Sie besser lesbaren Lösung greifen:
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print <<"ENDE"; <html> <head> <title>Titel</title> </head> <body bgcolor="#FFFFCC"> <h1>Ganz normales HTML</h1> <p>Perl und HTML sind manchmal wie Adam und Eva</p> </body> </html> ENDE
Sie können größere Textabschnitte, zum Beispiel kompletten HTML-Code, in einem Stück ausgeben. Dazu notieren Sie hinter dem print
-Befehl zwei <<
und direkt dahinter (ohne Leerzeichen dazwischen) den Namen eines Endbegrenzers, bis zu dem alles einfach als Text ausgegeben werden soll. Hinter dem (frei wählbaren) Namen des Endbegrenzers folgt in der Zeile des print
-Befehls das übliche Semikolon. Am Ende des auszugebenden Textes notieren Sie in einer eigenen Zeile den Namen des Endbegrenzers, dort jedoch ohne Semikolon am Ende. Es hat sich eingebürgert, für solche Namen von Labels Großbuchstaben zu verwenden, weil die Label so im Quelltext leichter sichtbar sind.
Bei CGI-Scripts kann der Inhalt der ausgegebenen Daten auch als HTTP-Befehl interpretiert werden. Die Anweisung:
print "Content-type: text/html\n\n";
ist ein typisches Beispiel dafür. Dabei wird ein einfacher HTTP-Header gesendet, der für die Kommunikation zwischen Server und Browser erforderlich ist. Eine andere für CGI-Scripts interessante Variante ist die folgende Anweisung (Beispiel):
print "Location: http://www.selfhtml.org/\n\n";
Auch dabei wird ein HTTP-Header ausgegeben, der eine Weiterleitung zu dem angegebenen URI bewirkt. Ein CGI-Script, das eine solche Location
-Anweisung enthält, braucht sonst keinen weiteren HTML-Code auszugeben.
Schreibt Daten auf die Standardausgabe oder in einen geöffneten Ausgabekanal, also etwa in eine Datei. Diese Funktion dient dazu, einzelne Datenelemente formatiert auszugeben. So lassen sich Dezimalzahlen beispielsweise ohne viel Umrechnung hexadezimal ausgeben, oder die Ausgabe von Gleitkommazahlen mit vielen Nachkommastellen lässt sich auf eine bestimmte Anzahl Nachkommastellen trimmen.
Die printf
-Funktion in Perl entspricht im wesentlichen der printf
-Funktion in C.
Erwartet als Parameter:
1. Datei-Handle = Optionale Angabe zum Ausgabekanal. Wenn Sie diese Angabe weglassen, wird auf die Standardausgabe STDOUT
geschrieben. Wenn Sie mit open eine Datei geöffnet haben und in diese schreiben wollen, müssen Sie das bei open
vergebene Datei-Handle angeben.
2. Formatstring = eine Zeichenkette, die für bestimmte auszugebende Elemente Formatbezeichner enthalten kann, und zwar entsprechend der speziellen Syntax der printf-Funktion (%-Zeichen-Syntax).
3. Ausgabeliste = ein oder mehrere Elemente, auf die sich die speziellen Formatbezeichner im Formatstring beziehen.
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); my $BruttoBetrag = 27.95; my $NettoBetrag = $BruttoBetrag / 1.16; print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title></head><body>\n"; printf "Das im Bruttobetrag %s enthaltene Netto beträgt ungerundet %.2f", $BruttoBetrag, $NettoBetrag; print "</body></html>\n";
Das Beispiel gibt mit Hilfe der printf
-Funktion die beiden Variablen $BruttoBetrag
und $NettoBetrag
aus. Der Wert von $NettoBetrag
wird rechnerisch gewonnen und stellt eine Bruchzahl mit vielen Nachkommastellen dar. In der Ausgabe mit printf
wird diese Zahl jedoch auf zwei Nachkommastellen reduziert ausgegeben.
Dazu notieren Sie in der auszugebenden Zeichenkette an der gewünschten Stelle einen Formatbezeichner. Solche Formatbezeichner beginnen mit einem Prozentzeichen %
. Dahinter folgen die Angaben zur Formatierung. Die folgende Tabelle listet die möglichen Formatbezeichner und deren Formatiermöglichkeiten auf.
Syntax | Bedeutung | Beispiel | Bewirkte Ausgabe |
---|---|---|---|
%c |
gibt das ASCII-Zeichen eines numerischen Zeichenwertes aus. Die Zahl kann z.B. dezimal oder hexadezimal angegeben werden. | printf "%c wie Paula", 0x50; |
P wie Paula |
%d |
gibt den Ganzzahlanteil einer Zahl in Dezimaldarstellung aus. Optional kann hinter dem % -Zeichen und vor dem d noch eine gewünschte Anzeigebreite der Zahl angegeben werden, z.B. %5d . In Verbindung mit HTML-Ausgaben ist dies jedoch nur innerhalb von Tags wie <pre> ...</pre> realisierbar. |
$PI = 3.141592653589793; |
Der Ganzzahlanteil von PI ist 3 |
%e |
gibt eine Zahl in Exponentialschreibweise aus | $PI = 3.141592653589793; |
PI exponential: 3.141593e+000 |
%E |
wie %e , nur mit E als Exponentialzeichen statt e. |
$PI = 3.141592653589793; |
PI exponential: 3.141593E+000 |
%f |
gibt eine Zahl mit Dezimalpunktdarstellung aus. Die Zahl nach dem Punkt ist die gewünschte Anzahl Nachkommastellen für die Ausgabe. Automatisch gerundet wird dabei nicht! | $Preis = 99; |
Der Preis beträgt 99.00 |
%g |
gibt eine Zahl automatisch in Exponentialschreibweise (wie bei %e ) oder in Dezimalpunktdarstellung (wie bei %f ) aus, abhängig von der Beschaffenheit der Zahl. |
$Zahl1 = 100, $Zahl2 = 10000000000000000; |
Die Zahlen: 100 und 1e+016 |
%G |
wie %g , nur mit E als Exponentialzeichen statt e. |
$Zahl = 10000000000000000; |
Die Zahl lautet 1E+016 |
%o |
gibt eine Zahl in oktaler Schreibweise aus, ansonsten wie %u . Das Oktalsystem kennt nur Ziffern von 0 bis 7. |
$Zahl = 100; |
Die Zahl lautet oktal 144 |
%u |
gibt eine Zahl als unsigned integer, also als positive Ganzzahl aus. Wenn die Zahl negativ ist, gibt Perl sie als die Differenz von der höchsten möglichen Integerzahl (4294967296) und der Zahl aus. | $Zahl1 = 100, $Zahl2 = -100; |
Die Zahlen sind 100 und 4294967196 |
%s |
gibt eine Zeichenkette (String) aus. | printf "PATH ist %s", $ENV{'PATH'}; |
PATH ist D:\PERL\BIN;C:\WINDOWS (Beispielausgabe) |
%x |
gibt eine Zahl in hexadezimaler Schreibweise aus, ansonsten wie %u . Das Hexadezimalsystem kennt als Ziffern 0 bis 9 und a bis f. |
$Zahl = 200; |
Die Zahl lautet hexadezimal c8 |
%X |
wie %x , nur mit A bis F als Ziffern statt a bis f. |
$Zahl = 200; |
Die Zahl lautet hexadezimal C8 |
%% |
notieren Sie, um das Formatbezeichnerzeichen, also das Prozentzeichen, selber auszugeben. | $Level = 100; |
wir haben 100% erreicht |
Zusätzlich zu diesen Formatbezeichnern stehen so genannte Flags zur Verfügung, mit deren Hilfe sich die Ausgabe noch feiner justieren lässt. Flags müssen unmittelbar hinter dem Prozentzeichen für Formatbezeichner notiert werden. Die folgende Tabelle listet mögliche Flags auf:
Syntax | Bedeutung | Beispiel | Bewirkte Ausgabe |
---|---|---|---|
[blank] |
Leerzeichen vor positiven Zahlen erzwingen. Sinnvoll, wenn diese in Kolonne mit anderen Zahlen stehen, die auch negativ sein können. | $Zahl1 = 100, $Zahl2 = -100; |
100 -100 |
- |
Zahlen mit erzwungener Anzeigebreite linksbündig ausrichten (Voreinstellung ist rechtsbündig). |
printf "%-10d Zugriffe", 1234;
|
1234 Zugriffe |
0 |
Zahl mit erzwungener Anzeigebreite mit Nullen auffüllen, falls die Zahl kleiner ist. |
printf "%010d Zugriffe", 1234;
|
0000001234 Zugriffe |
# |
Hexadezimal- oder Oktalzahl mit entsprechendem Bezeichner für die übliche Schreibweise versehen. |
printf "100 Hex = %#x, 100 Okt = %#o", 100, 100;
|
100 Hex = 0x64, 100 Okt = 0144 |
Wenn Sie die Daten lediglich formatieren wollen, ohne sie auszugeben, verwenden Sie bitte die sprintf-Funktion.
Liest eine anzugebende Anzahl Zeichen aus einer Datei ab der aktuellen Position des Dateizeigers in einen Skalar ein.
Erwartet als Parameter:
1. das Datei-Handle.
2. einen Skalar, in dem die eingelesenen Zeichen gespeichert werden.
3. die Anzahl der zu lesenden Zeichen.
4. (optional) Offset - wenn die Zeichen in dem Zeichenkettenskalar (2.), in den eingelesen werden, nicht ab dem ersten Zeichen beginnen sollen, sondern ab einem Zeichen n, das als Offset angegeben wird (die Zählung beginnt bei 0).
Gibt die Anzahl eingelesener Zeichen zurück. Wenn das Dateiende erreicht wurde, wird 0
zurückgegeben. Wenn ein Fehler auftritt, wird undef
zurückgegeben.
[Sat Feb 03 17:24:44 2001] [error] [client 127.0.0.1] File does not exist: /usr/web/src/formate.css
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title>\n"; print "</head><body>\n"; my $Ausgabe; open(ERRORDATEI, "</usr/logs/error.log") || die "Log-Datei nicht gefunden!"; my $geleseneZeichen = read(ERRORDATEI, $Ausgabe, 26); close(ERRORDATEI); print "gelesene Zeichen: $geleseneZeichen; gelesener Inhalt: $Ausgabe\n"; print "</body></html>\n";
Das Beispiel zeigt im ersten Teil den Inhalt einer Datei namens error.log. Die Datei enthält eine Zeile, in der ein aufgetretener Fehler protokolliert ist. Im zweiten Teil des Beispiels liest ein CGI-Script diese Datei aus, aber nicht komplett, sondern nur 26 Zeichen. Da der Dateizeiger nach dem Öffnen der Datei mit open auf 0 steht, liest der im Beispiel notierte read
-Befehl die ersten 26 Zeichen aus der Datei. Zur Kontrolle gibt das Script im Beispiel die Anzahl der eingelesenen Zeichen aus, die es durch den Rückgabewert von read
in dem Skalar $geleseneZeichen
ermittelt. Ferner gibt das Script die eingelesene Zeichenkette aus. Im Beispiel ist das genau der Teil, der den Zeitstempel in der Datei error.log markiert, also [Sat Feb 03 17:24:44 2001]
. Dies sind die ersten 26 Zeichen.
Um den Dateizeiger vor dem Lesen mit read
an eine andere Stelle zu positionieren, können Sie die Funktion seek verwenden.
Liest Einträge in einem Verzeichnis, das zuvor mit der Funktion opendir geöffnet wurde.
Erwartet als Parameter:
1. das Verzeichnishandle, das bei opendir
vergeben wurde.
Gibt den jeweils nächsten Verzeichniseintrag zurück, wenn der Rückgabewert in einem Skalar gespeichert wird, zum Beispiel:
$Eintrag = readdir(DIR);
Gibt alle Einträge des Verzeichnisses zurück, wenn der Rückgabewert in einer Liste gespeichert wird, zum Beispiel:
@Eintraege = readdir(DIR);
Verzeichniseinträge sind sichtbare Dateien, Verzeichnisse sowie die Platzhalter für das aktuelle Verzeichnis (.
) und für das nächsthöhere Verzeichnis (..
).
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); my $Verzeichnis = "/usr/web/ars_vivendi"; my $URIVerzeichnis = "/ars_vivendi"; opendir(DIR, $Verzeichnis) || die "$Verzeichnis: $!"; my @Dateien = readdir(DIR); closedir(DIR); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title></head><body>\n"; foreach(@Dateien) { if($_ =~ /.+\.htm*/) { print "<a href=\"$URIVerzeichnis/$_\">$URIVerzeichnis/$_</a><br>\n"; } } print "</body></html>\n";
Im Beispiel wird in dem Skalar $Verzeichnis
der Pfad eines Verzeichnisses gespeichert ("/usr/web/ars_vivendi"
). In einem zweiten Skalar $URIVerzeichnis
wird ein zweiter Pfad ("/ars_vivendi"
) gespeichert. Der Grund ist, dass im Beispiel "/usr/web"
als Wurzelverzeichnis (DocumentRoot) des installierten Webservers vorausgesetzt wird. Dann ist "/ars_vivendi"
ein Verzeichnis unterhalb der DocumentRoot.
Mit der Funktion opendir
wird das Verzeichnis geöffnet. Mit Hilfe von readdir
wird der Verzeichnisinhalt in eine Liste @Dateien
eingelesen. Anschließend wird das Verzeichnis durch Aufruf der Funktion closedir geschlossen.
Das Beispiel gibt dann HTML-Code aus. Dabei wird die Liste der Verzeichniseinträge analysiert. Einträge, in denen das Suchmuster .+\.htm*
vorkommt, werden zeilenweise ausgegeben, und zwar umrahmt von HTML-Auszeichnungen, die den jeweiligen Eintrag als Verweis anklickbar machen. Zur korrekten Adressierung der anklickbaren HTML-Dateinamen wird der Skalar $URIVerzeichnis
verwendet.
Positioniert den Lesezeiger in einem Verzeichnis, das zuvor mit der Funktion opendir geöffnet wurde, wieder auf den ersten Eintrag. Dies kann sinnvoll sein, wenn Sie das Verzeichnis mit readdir bereits eingelesen haben, das Verzeichnishandle aber zu einem erneuten Einlesen des Verzeichnisinhalts verwenden möchten.
Erwartet als Parameter:
1. das Verzeichnishandle, das bei opendir
vergeben wurde.
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); my $Verzeichnis = "/usr/work"; print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title></head><body>\n"; opendir(DIR, $Verzeichnis) || die "$Verzeichnis: $!"; my @Eintraege = readdir(DIR); my $Eintrag; foreach $Eintrag (@Eintraege) { if($Eintrag =~ /.+\.bak/) { unlink($Verzeichnis."/".$Eintrag); } } rewinddir(DIR); @Eintraege = ""; @Eintraege = readdir(DIR); foreach $Eintrag (@Eintraege) { print "$Eintrag<br>\n"; } print "</body></html>\n"; closedir(DIR);
Das Beispiel liest zunächst alle Einträge des Verzeichnisses $Verzeichnis
in die Liste @Eintraege
ein. Diese Liste wird anschließend nach Dateien des Typs *.bak (typische Endung für Sicherungs-Dateien) durchsucht. Dateien mit dieser Endung werden im Beispiel gelöscht (mit unlink). Nachdem diese Aktion beendet ist, wird der Verzeichniszeiger mit rewinddir(DIR)
zurückgesetzt, denn das Verzeichnis soll nun mit dem gleichen immer noch geöffneten Verzeichnishandle DIR
nochmals eingelesen werden. Beim zweiten Einlesen werden alle vorhandenen Einträge ausgegeben. Dateien des Typs *.bak sollten eigentlich nicht mehr dabei sein. Oft geschieht das Neueinlesen jedoch noch, bevor die Dateien vom Betriebssystem gelöscht sind, und es werden deshalb doch noch die alten Einträge ausgegeben.
Positioniert den Dateizeiger eines Dateihandles, das zuvor mit open erzeugt wurde, an eine beliebige Stelle innerhalb der Datei.
Erwartet als Parameter:
1. das Handle der geöffneten Datei.
2. Byteposition innerhalb der Datei, abhängig von der im dritten Parameter angegebenen Bezugsposition
3. Bezugsposition für die Angabe im zweiten Parameter. Diese kann die Werte 0, 1 oder 2 haben:
ISBN 3-7723-7514-6
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); my $Datei = "isbn.txt"; my $ISBNummer; open(DATEI, "<$Datei"); seek(DATEI, 5, 0); read(DATEI, $ISBNummer, 13); close(DATEI); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title>\n"; print "ISBN-Nummer: $ISBNummer"; print "</body></html>\n";
Das Beispiel zeigt im ersten Teil den Inhalt einer Datei namens isbn.txt. Die Datei enthält eine Zeile, in der eine ISBN-Nummer notiert ist, wobei die eigentliche ISBN-Nummer jedoch erst an Position 5 beginnt. Im zweiten Teil des Beispiels liest ein CGI-Script diese Datei aus, aber nicht komplett, sondern nur ab Position 5, und von dort an 13 Zeichen.
Da der Dateizeiger nach dem Öffnen der Datei mit open auf 0 steht, wird er mit seek(DATEI, 5, 0)
auf Position 5 vom Dateianfang her gerechnet gesetzt. Anschließend werden die 13 Zeichen der ISBN-Nummer mit read eingelesen. Zur Kontrolle gibt das Script im Beispiel die eingelesenen Daten aus.
Die Funktion seek
können Sie nur in Verbindung mit read
oder write verwenden, aber nicht in Verbindung mit sysread oder syswrite. Benutzen Sie in diesem Fall die Funktion sysseek.
Positioniert den Verzeichniszeiger eines Verzeichnishandles, das zuvor mit opendir erzeugt wurde, auf einen beliebigen Eintrag innerhalb des Verzeichnisses. Voraussetzung dazu ist, dass die Funktion telldir angewendet wird, um die internen Positionsnummern der Verzeichniseinträge zu ermitteln.
Erwartet als Parameter:
1. das Verzeichnishandle, das bei opendir
vergeben wurde.
2. die interne Positionsnummer eines Verzeichniseintrags, auf den positioniert werden soll. Diese interne Positionsnummern können nur durch Aufruf der Funktion seekdir
ermittelt werden. Es handelt sich um vom Dateisystem des Rechners gelieferte Adressen, also nicht um einfache fortlaufende Nummern!
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); my $Verzeichnis = "/usr/texte"; opendir(DIR, $Verzeichnis) || die "$Verzeichnis: $!"; my @Positionen; my @Eintraege; for(my $i=0;$i<10;$i++) { $Eintraege[$i] = readdir(DIR); $Positionen[$i] = telldir(DIR); } print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title></head><body>\n"; for(my $i=0;$i<10;$i++) { print "<p>Eintraege[$i] = $Eintraege[$i]<br>\n"; print "Positionen[$i] = $Positionen[$i]</p>\n"; } seekdir(DIR, $Positionen[5]); my $Eintrag = readdir(DIR); print "<p>Positioniert auf Positionen[5] und Eintrag gelesen: $Eintrag</p>\n"; print "</body></html>\n"; closedir(DIR);
Das Beispiel leistet nichts Produktives, es dient nur zur Verdeutlichung, und es dient dazu, das Prinzip der internen Positionsnummern zu verstehen. In dem Beispiel wird ein Verzeichnis mit opendir geöffnet. Die ersten zehn Einträge des Verzeichnisses werden danach in einer for-Schleife mit readdir eingelesen. Dabei werden auch die Positionsnummern der eingelesenen Einträge gespeichert, und zwar in dem Array @Positionen
. Das CGI-Script gibt zur Kontrolle die zehn eingelesenen Einträge und deren ermittelte Positionsnummern aus. Um die Funktion seekdir
zu testen, wird auf eine der ermittelten Positionsnummern ($Positionen[5]
) positioniert. Der nächste Verzeichniseintrag wird noch mal eingelesen und zur Kontrolle ausgegeben.
Wenn Sie mit seekdir
auf einen Verzeichniseintrag positionieren und dann readdir
anwenden, wird nicht derjenige Verzeichniseintrag eingelesen, auf den Sie positioniert haben, sondern der nächste!
Wählt den Default-Ein-/Ausgabekanal für nachfolgende Lese-/Schreiboperationen aus.
Erwartet als Parameter:
1. das Handle des gewünschten Ein-/Ausgabekanals. Das kann ein Handle einer zuvor mit open geöffneten Datei sein oder einer der Standardkanäle.
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/plain\n\n"; open(DATEI, ">>/usr/webconfig/users.txt") || die "$!"; my $User = "Stefan"; select(DATEI); print "\nuser=$User"; close(DATEI); select(STDOUT); print "$User in Datei geschrieben";
Im Beispiel wird zunächst ein HTTP-Header erzeugt. Die print
-Funktion schreibt dabei erst mal auf den Standardausgabekanal. Anschließend wird eine Datei zum anhängenden Schreiben geöffnet. Dabei wird das Handle mit dem Namen DATEI
erzeugt. Anschließend wird dieses Handle mit select(DATEI)
als das aktive Handle ausgewählt. Die nachfolgende print-Funktion bezieht sich dadurch automatisch auf das ausgewählte Handle. Um in die Datei zu schreiben, ist also:
select(DATEI);
print "\nuser=$User";
gleichbedeutend mit:
print DATEI "\nuser=$User";
.
Nachdem die neue Zeile in die Datei geschrieben und diese geschlossen wurde, wird - wiederum mit select
- der Standardausgabekanal STDOUT
als neuer aktiver Kanal ausgewählt. Der nachfolgende print
-Befehl, der eine Bestätigung ausgibt, funktioniert nur, weil zuvor STDOUT
als aktiver Kanal ausgewählt wurde. Andernfalls wäre der aktive Kanal undefiniert, da der zuvor als aktiv ausgewählte Kanal DATEI
mittlerweile geschlossen wurde.
Öffnet eine Datei ebenso wie open. Während open
jedoch die bequeme Art der Umleitung (mit >
, >>
, <
, ...) an der Kommandozeile nachahmt, wird bei sysopen
direkt der betriebssystemeigene Befehl zum Öffnen einer Datei benutzt. Der Vorteil ist, dass Sie genauer angeben können, wie Sie die Datei öffnen wollen. Der Nachteil ist, dass es Probleme mit Betriebssystemen gibt, die nicht alle Features unterstützen. Das Perl-Script lässt sich dann möglicherweise nicht mehr in verschiedenen Umgebungen ausführen.
Erwartet als Parameter:
1. den Namen des Datei-Handles (frei wählbar),
2. den Namen der Datei, wenn erforderlich mit relativem oder absolutem Pfadnamen,
3. den Modus, in dem die Datei geöffnet werden kann. Dazu ist es ratsam, das Standardmodul Fcntl
einzubinden, in dem Konstanten für erlaubte Werte definiert sind. Folgende Konstanten sind dann erlaubt:
O_RDONLY
bedeutet: Datei nur zum Lesen öffnen,O_WRONLY
bedeutet: Datei nur zum Schreiben öffnen,O_RDWR
bedeutet: Datei zum Lesen und Schreiben öffnen.|
) mit folgenden Zusatzkonstanten verknüpfen:O_APPEND
bedeutet: Schreiben nur am Ende der Datei,O_CREAT
bedeutet: Datei anlegen, falls sie nicht existiert,O_EXCL
in Verbindung mit O_CREAT
bedeutet: Abbrechen und false
zurückgeben, wenn die Datei schon existiert,O_NONBLOCK
bedeutet: beim Öffnen der Datei nicht blockieren (ältere Version: O_NDELAY
),O_SYNC
bedeutet: nach jedem Schreibvorgang wird die Synchronisationsfunktion fsync()
aufgerufen,O_TRUNC
bedeutet: die existierende Datei wird auf 0 Byte gekürzt, ohne gelöscht zu werden.4. (optional) eine Angabe für die Zugriffsrechte, mit denen die Datei geöffnet werden soll. Die Angabe ist dabei die unter Unix übliche Bezeichnung der Zugriffsrechte für Welt, Gruppe und Eigner in Oktalschreibweise mit führender 0 (z.B. 0440
) und nicht in Anführungszeichen zu notieren.
Wenn die Datei geöffnet werden kann, gibt die Funktion den Wert true
zurück, andernfalls den Wert false
.
#!/usr/bin/perl -w use strict; use Fcntl; my $Datei = "/usr/geistesblitze/aktuell.txt"; sysopen(DATEI, $Datei, O_WRONLY | O_APPEND, 0440) || die "$Datei: $!"; print DATEI "Neugier killte die Katze\n"; close(DATEI);
Im Beispiel wird eine Textdatei mit sysopen
geöffnet. Dabei wird bestimmt, dass die Datei nur zum Schreiben geöffnet wird, und zwar so, dass geschriebene Inhalte an die vorhandene Datei angehängt werden (erreicht durch bitweise Verknüpfung von O_APPEND
). Mit print
wird ein Satz in die Datei geschrieben. Anschließend wird die Datei geschlossen. Dazu können Sie die übliche Funktion close verwenden.
Der Befehl use Fcntl
zu Beginn ist erforderlich, um Zugriff auf Konstanten wie O_WRONLY
und O_APPEND
zu erhalten.
Liest eine anzugebende Anzahl Zeichen aus einer Datei ab der aktuellen Position des Dateizeigers in einen Skalar ein. Die Datei sollte in den meisten Fällen sinnvollerweise mit sysopen geöffnet worden sein. Ansonsten gelten für sysread
die gleichen Regeln zum Aufruf und beim Rückgabewert wie bei read.
Positioniert den Dateizeiger eines Dateihandles, das zuvor sinnvollerweise mit sysopen erzeugt wurde, an eine beliebige Stelle innerhalb der Datei. Ansonsten gelten für sysseek
die gleichen Regeln zum Aufruf und beim Rückgabewert wie bei seek.
Schreibt eine anzugebende Anzahl Zeichen aus einer ebenfalls anzugebenden Variablen ab der aktuellen Position innerhalb dieser Variablen in eine Datei. Die Datei sollte sinnvollerweise mit sysopen geöffnet worden sein.
Erwartet als Parameter:
1. das Datei-Handle.
2. einen Skalar, der die Zeichen zum Schreiben in die Datei enthält.
3. (optional) die Anzahl der in die Datei zu schreibenden Zeichen.
4. (optional) Offset - wenn die zu schreibenden Zeichen in dem Zeichenkettenskalar (2.) nicht ab dem ersten Zeichen beginnen, sondern ab einem Zeichen n, können Sie n als Offset angeben (die Zählung beginnt bei 0).
Wenn der Skalar mehr Daten enthält als geschrieben werden sollen, werden trotzdem nur so viele Zeichen geschrieben wie angegeben. Wenn der Skalar weniger Daten enthält als geschrieben werden sollen, werden nur so viele Zeichen geschrieben, wie der Skalar ab dem Offset noch enthält. Wenn Sie keine Anzahl zu schreibender Zeichen angeben, wird der komplette Inhalt des Skalars in die Datei geschrieben.
syswrite
gibt die Anzahl tatsächlich geschriebener Zeichen zurück. Im Fehlerfall wird undef
zurückgegeben.
#!/usr/bin/perl use strict; use Fcntl; my $Datei = "/usr/bin/mycodes/mysecret.sys"; my $Daten = "sdclknavaoertoerigjvimfvlkmdfghjdfbjdfihgjsobijsngohijsrotigueiufgulvbdkjbndfkhv"; my $Block = 8; sysopen(DATEI, $Datei, O_WRONLY | O_EXCL) || die "$Datei: $!"; for(my $i=0;$i<10;$i++) { my $Offset = $i * $Block; syswrite(DATEI,$Daten,$Block,$Offset); } close(DATEI);
Das Beispiel schreibt eine Zeichenkette, die in $Daten
gespeichert ist, blockweise in eine Datei. Dazu stehen die Aufrufe von sysread
in einer for-Schleife. Die Schleife hat 10 Durchläufe, da die Länge von $Daten
80 Zeichen beträgt und pro Schreibvorgang 8 Zeichen (in dem Skalar $Block
definiert) geschrieben werden sollen. Dabei ist es wichtig, jedesmal den Offset neu zu berechnen, damit immer die jeweils nächsten 8 Zeichen geschrieben werden, und nicht immer wieder nur die ersten 8.
Das Beispiel selbst ist in dieser Form nicht besonders praxisrelevant, denn bei der kleinen Datenmenge empfiehlt es sich, den gesamten Inhalt von $Daten
in einem Rutsch in die Datei zu schreiben. Aber das Prinzip lässt sich anwenden, wenn die Datenmenge aus anderen Quellen dynamisch gewonnen wird, wobei sie ja sehr groß sein kann.
Ermittelt die aktuelle Byteposition des Dateizeigers eines Dateihandles, das zuvor mit open erzeugt wurde.
Erwartet als Parameter:
1. das Datei-Handle.
Gibt die aktuelle Byteposition zurück. Wenn ein Fehler aufgetreten ist, wird -1
zurückgegeben.
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); my $Datei = "/usr/info/readme.txt"; my @Zeilenanfaenge = ""; open(DATEI, "<$Datei") || die "$Datei: $!"; $Zeilenanfaenge[0] = tell(DATEI); my $i = 0; while(<DATEI>) { $i++; $Zeilenanfaenge[$i] = tell(DATEI); } close(DATEI); $i = 1; print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title></head><body>\n"; foreach (@Zeilenanfaenge) { print "Zeile $i beginnt in der Datei bei Offset $_<br>\n"; $i++; } print "</body></html>\n";
Das Beispiel öffnet mit open
eine Textdatei und liest sie in einer while-Schleife zeilenweise ein. Dabei wird direkt nach dem Öffnen und bei jedem Schleifendurchgang die aktuelle Position des Dateizeigers mit tell
ermittelt und im jeweils nächsten Element des Arrays @Zeilenanfaenge
gespeichert. Anschließend wird HTML-Code erzeugt. Dabei werden die gespeicherten Offset-Positionen der Zeilenanfänge in einer foreach-Schleife ausgegeben.
Ermittelt die interne Positionsnummer des Verzeichniseintrags, auf dem der Verzeichniszeiger eines Verzeichnishandles steht, das zuvor mit opendir erzeugt wurde.
Erwartet als Parameter:
1. das Verzeichnishandle, das bei opendir
vergeben wurde.
Ein vollständiges Beispiel mit Erläuterung der zusammenhängenden Funktionen telldir
und seekdir
wird bei der Funktion seekdir behandelt.
Diese Funktion dient dazu, Daten, die mit format formatiert wurden, datensatzweise in eine Datei zu schreiben, die zuvor mit open geöffnet wurde. Beispiele werden im Zusammenhang mit der Funktion format
beschrieben.
Funktionen für Datei- und Verzeichnis-Management | |
Funktionen für Datum und Uhrzeit | |
SELFHTML/Navigationshilfen Perl Perl-Funktionen |
© 2005 Impressum