Perl/Funktionen für Ein-/Ausgabe und Lesen/Schreiben von Daten

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

[Bearbeiten] 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, sodass 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.

Beachten Sie: 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 Browser vom Webserver Daten angefordert hat, haben Sie mit diesen Funktionen keinen Zugriff (auch wenn das manchmal von einigen weniger erfahrenen Perl-Bastlern gewünscht und an manchen Stellen diskutiert wird)!

[Bearbeiten] Datei-Handles

Bei Dateioperationen kommen Datei-Handles zum Einsatz. Seit Perl 5.005 können solche Handles als normale Variablen deklariert werden. Diese neuere Version wird allgemein empfohlen, insbesondere deshalb, weil diese Handles gespeichert oder an Subroutinen weitergereicht werden können.

Beispiel
# alte version
open( HANDLE, "<", $file ) or die("$!");
while(<HANDLE>){
  # ...
}
close( HANDLE );
 
# neue Version
open( my $handle, "<", $file ) or die("$!");
while(<$handle>){
  # ...
}
close( $handle );
Gegenüberstellung der zwei Versionen des Datei-Handles.

[Bearbeiten] binmode - Datei binär behandeln

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. 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 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.
Beispiel
#!/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") or die("File not found $!");
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.
Beachten Sie: 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.

[Bearbeiten] close - Datei schließen

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.

Beachten Sie: Wenn Sie eine zuvor geöffnete Datei nicht explizit mit close schließen, wird die Datei von Perl beim Beenden des Scripts automatisch geschlossen.

[Bearbeiten] closedir - Verzeichnis schließen

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.

[Bearbeiten] eof - auf Dateiende prüfen

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.

Beispiel
#!/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") 
    or die("File not found $!");
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.
Beachten Sie: 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.

[Bearbeiten] fileno - Nummer einer geöffneten Datei

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.

Beispiel
#!/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")
     or die("File not found $!");
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.

[Bearbeiten] flock - geöffnete Datei vor Zugriffen schützen

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 dasselbe 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 (sofern Ihr Perl-Script in einer solchen Systemumgebung laufen sollte).

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.
  • Nummer 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),
  • Nummer 2 oder Konstante LOCK_EX bedeutet exclusive (keinem anderen Prozess irgendeinen Zugriff auf die Datei erlauben),
  • Nummer 8 oder Konstante LOCK_UN bedeutet unlock (Zugriffsschutz ausdrücklich wieder aufheben).
  • Nummer 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.

Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
use Fcntl ':flock';
$| = 1;
 
open(DATENDATEI, "<", "/db/daten.csv")
     or die("File not found $!");
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.
Beachten Sie: 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 lediglich empfehlenden Charakter. Der Zugriffsschutz ist nur dann wirksam, wenn alle Prozesse, die auf die Datei zugreifen, flock beachten.

[Bearbeiten] format - Daten vor dem Ausgeben formatieren

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 Browser zeichenorientiert arbeiten.

Beispiel
#!/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
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.

Beispiel
#!/usr/bin/perl -w
 
use strict;
 
format STDOUT =
Seite @<<    @>>>>>>>
$%, $~
.
write;
In Beispiel 2 wird folgendes ausgegeben:
Seite 0        STDOUT
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:

Beispiel
#!/usr/bin/perl -w
 
use strict;
use vars qw($Zeile);
 
open(DATEI,"<", "/usr/texte/daten.txt")
    or die("File not found $!");
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.
Beachten Sie: Die Variable $Zeile muss im obigen Beispiel global deklariert werden. Daher die Anweisung use vars qw($Zeile); zu Beginn.

[Bearbeiten] getc - nächstes Zeichen lesen

Liest ein Zeichen aus einer zuvor geöffneten Datei und positioniert den Dateizeiger um ein Zeichen weiter.

Erwartet als Parameter:

  1. das Datei-Handle.
Beispiel
#!/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")
    or die("File not found $!");
my $Bytes = 0;
while(! eof(DATEI)) {
 my $Zeichen = getc(DATEI);
 print "$Zeichen";
 $Bytes++;
}
close(DATEI);
print "</pre><strong>", $Bytes, " Zeichen gelesen!</strong>\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 mit ausgegeben.

[Bearbeiten] open - Datei öffnen

Ö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-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.

Beispiel
#!/usr/bin/perl -w
 
use strict;
 
open(DATEI, "<", "/tmp/server.cfg")
     or die "Datei nicht gefunden";
my @Zeilen = <DATEI>;
close(DATEI);
 
my @NeueZeilen;
foreach(@Zeilen) {
  $_ =~ s/#.*//;
  push(@NeueZeilen,$_) if $_ !~ /^\s*\n/;
}
open(DATEI, ">", "/tmp/server.cfg") 
  or 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.
Beachten Sie: 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. Sieh auch http://perldoc.perl.org/functions/open.html

[Bearbeiten] opendir - Verzeichnis öffnen

Ö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.

Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
my $Verzeichnis = "/daten/web";
opendir(DIR, $Verzeichnis) or 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 Windows läuft. Wenn Sie in einer 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.
Beachten Sie: 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).

[Bearbeiten] print - Daten ausgeben

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 benutzen.
  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.

Beispiel
#!/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><th>Umgebungsvariable</th><th>Aktueller Wert</th></tr>\n";
foreach (keys %ENV) {
    print "<tr><th>", $_, "</th><td>", $ENV{$_}Eintrag, "</td></tr>\n";
}
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.
Beachten Sie: 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.

[Bearbeiten] printf - Daten formatiert ausgeben

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.
Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
my $BruttoBetrag = 27.95;
my $NettoBetrag = $BruttoBetrag / 1.19;
 
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;
printf "Der Ganzzahlanteil von PI ist %d", $PI;
Der Ganzzahlanteil von PI ist 3
%e gibt eine Zahl in Exponentialschreibweise aus $PI = 3.141592653589793;
printf "PI exponential: %e", $PI;
PI exponential: 3.141593e+000
%E wie %e, nur mit E als Exponentialzeichen statt e. $PI = 3.141592653589793;
printf "PI exponential: %E", $PI;
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;
printf "Der Preis beträgt %.2f", $Preis;
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;
printf "Die Zahlen: %g und %g", $Zahl1, $Zahl2;
Die Zahlen: 100 und 1e+016
%G wie %g, nur mit E als Exponentialzeichen statt e. $Zahl = 10000000000000000;
printf "Die Zahl lautet %G", $Zahl;
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;
printf "die Zahl lautet oktal %o", $Zahl;
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;
printf "Die Zahlen: %u und %u", $Zahl1, $Zahl2;
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;
printf "die Zahl lautet oktal %x", $Zahl;
Die Zahl lautet hexadezimal c8
%X wie %x, nur mit A bis F als Ziffern statt a bis f. $Zahl = 200;
printf "die Zahl lautet oktal %X", $Zahl;
Die Zahl lautet hexadezimal C8
%% notieren Sie, um das Formatbezeichnerzeichen, also das Prozentzeichen, selber auszugeben. $Level = 100;
printf "wir haben %d%% erreicht", $Level;
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;
printf "% d%\n% d", $Zahl1, $Zahl2;
 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
Beachten Sie: Wenn Sie die Daten lediglich formatieren wollen ohne sie auszugeben, verwenden Sie bitte die sprintf-Funktion.

[Bearbeiten] read - bestimmte Anzahl Zeichen lesen

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 sie 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.

Beispiel
[Sat Feb 07 17:24:44 2007] [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, "</var/log/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 07 17:24:44 2007]. Dies sind die ersten 26 Zeichen.
Beachten Sie: Um den Dateizeiger vor dem Lesen mit read an eine andere Stelle zu positionieren, können Sie die Funktion seek verwenden.

[Bearbeiten] readdir - Verzeichniseinträge ermitteln

Liest Einträge eines Verzeichnisses, 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 (..).

Beispiel
#!/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 dafür 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.

[Bearbeiten] rewinddir - auf ersten Verzeichniseintrag positionieren

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.
Beispiel
#!/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 demselben 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.

[Bearbeiten] seek - Dateizeiger positionieren

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:
  • 0 bedeutet absolut vom Dateianfang (Position 0) aus gerechnet,
  • 1 bedeutet relativ vom der aktuellen Position des Dateizeigers aus gerechnet,
  • 2 bedeutet absolut vom Dateiende gerechnet (im Normalfall sollte die Angabe beim zweiten Parameter in diesem Fall eine negative Zahl sein).
Beispiel
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.
Beachten Sie: 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.

[Bearbeiten] seekdir - Verzeichniszeiger positionieren

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!
Beispiel
#!/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 einmal eingelesen und zur Kontrolle ausgegeben.
Beachten Sie: 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!

[Bearbeiten] select - Ein-/Ausgabekanal auswählen

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.
Beispiel
#!/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 zuerst 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.

[Bearbeiten] sysopen - Datei systemnah öffnen

Ö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 besteht darin, dass Sie genauer angeben können, wie Sie die Datei öffnen wollen. Der Nachteil ist aber, 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.
  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.

Für den Modus sind folgende Konstanten 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.
  • Diese Konstanten können Sie durch bitweises Oder (einfacher Senkrechtstrich |) 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.


Wenn die Datei geöffnet werden kann, gibt die Funktion den Wert true zurück, andernfalls den Wert false.

Beispiel
#!/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.
Beachten Sie: Der Befehl use Fcntl zu Beginn ist erforderlich, um Zugriff auf Konstanten wie O_WRONLY und O_APPEND zu erhalten.

[Bearbeiten] sysread - bestimmte Anzahl Zeichen systemnah lesen

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.

[Bearbeiten] sysseek - Dateizeiger systemnah positionieren

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.

[Bearbeiten] syswrite - bestimmte Anzahl Zeichen systemnah schreiben

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.

Beispiel
#!/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, jedes Mal den Offset neu zu berechnen, damit immer die jeweils nächsten 8 Zeichen geschrieben werden, und nicht immer wieder nur die ersten 8.
Beachten Sie: 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.

[Bearbeiten] tell - Position des Dateizeigers ermitteln

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.

Beispiel
#!/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.

[Bearbeiten] telldir - Position des Verzeichniszeigers ermitteln

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.

[Bearbeiten] write - formatierte Daten schreiben

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.

Meine Werkzeuge
Namensräume

Varianten
Aktionen
Übersicht
Index
Mitmachen
Werkzeuge
Spenden
SELFHTML