cgicorner.ch

Informationen rund um Perl/CGI

Sie sind hier: Home > CGI Hilfe > Tutorial > Kapitel 9 - Dateien lesen/schreiben

Tutorial - Kapitel 9: Datei Ein- und Ausgabe

Voraussetzungen für dieses Kapitel

  • Webserver mit Perl/CGI-Unterstützung

Einleitung

Ein wichtiger Bestandteil von CGI-Scripts ist sicherlich das lesen und speichern von Dateien. Dies kann für Daten oder Konfigurationen sehr hilfreich sein, vor allem, wenn keine Datenbank zur Verfügung steht. Dateioperationen sind mit Perl sehr einfach.

Datei Test Operatoren

Bevor wir direkt mit lesen und schreiben anfangen, zuerst noch einige Hinweise, wie man testen kann, ob die Datei überhaupt gelesen und geschrieben werden kann. Dazu gibt es unter Perl sog. "File Test Operators". Diese wären im Einzelnen:

-e Datei existiert
-z Datei existiert und hat eine Grösse von 0 Bytes
-s Datei existiert und hat eine Grösse von mehr als 0 Bytes
-r Datei ist lesbar
-w Datei ist schreibbar
-x Datei ist ausführbar
-d Datei ist ein Verzeichnis

Diese Liste ist nicht vollständig. Die komplette Liste findet man in Rex Swain's HTMLified Perl 5 Reference Guide. Für die meisten Zwecke dürfte diese Tabelle aber genügen.

Der Check ist dann ganz einfach:

if (-e "datei.txt") {
  print "Datei \"datei.txt\" existiert!";
} else {
  print "Datei \"datei.txt\" existiert nicht!";
}

Dateien lesen

Eine Datei wird unter Perl immer mit einem File-Handler angesprochen, Dabei kann ein beliebiger Name gewählt werden (gleiche Anforderungen wie an eine Variable, also keine Leerzeichen, Umlaute etc.). Die Datei kann dann entweder in ein Array (pro Zeile ein Eintrag im Array) eingelesen werden, oder gleich mit einer While-Schleife verarbeitet werden. Folgende zwei Beispiele geben die Datei test.txt 1:1 an den Browser aus:

fileread1.cgi:

#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<html><body><pre>";

if (-r test.txt) {
  open(INPUTFILE,"test.txt");
  my @fileContent=<INPUTFILE>;
  close(INPUTFILE);
  foreach (@fileContent) {
    print "$_";
  }
} else {
  print "FEHLER: Datei kann nicht gelesen werden...";
}
print "</pre></body></html>";

Zuerst wird überprüft, ob die Datei test.txt lesbar ist. Wenn ja wird die Datei mit dem Dateihandler INPUTFILE geöffnet. Danach wird der Inhalt der Datei in das Array @fileContent eingelesen und die Datei wieder geschlossen. Am Schluss wird das Array mit einer foreach-Schleife noch zeilenweise verarbeitet und jede Zeile (Inhalt gespeichert in der Standard-Variable $_) ausgegeben.

Wer sich nicht an das $_ gewöhnen will, kann auch folgende Schreibweise verwenden:

foreach $aktuelleZeile (@fileContent) {
  print "$aktuelleZeile";
}

Eleganter ist in diesem Fall die Lösung mit der direkten Ausgabe an den Browser, da dann nicht noch zuerst die ganze Datei in ein Array abgelegt werden muss, was - besonders bei grösseren Dateien - zusätzlichen Speicher benötigt:

fileread2.cgi

#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<html><body><pre>";

if (-r test.txt) {
  open(INPUTFILE,"test.txt");
  while (<INPUTFILE>) {
    print "$_";
  }
  close(INPUTFILE);
} else {
  print "FEHLER: Datei kann nicht gelesen werden...";
}
print "</pre></body></html>";

Der Anfang ist wieder identisch: nach dem Check, ob die Datei lesbar ist, wird die Datei geöffnet (Dateihandler INPUTFILE). Nun wird in einer While-Schleife die Datei zeilenweise ausgegeben (Wichtig: die Datei muss immer noch geöffnet sein! Der close-Befehl kommt erst nach der While-Schleife).

Dateien schreiben

Das Schreiben von Dateien ist noch simpler: Zuerst muss die Datei zum schreiben geöffnet werden. Dazu verwendet man das unter vielen Betriebssystemen bekannte >-Zeichen:

> Datei erstellen, wenn Datei bereits existiert: überschreiben
>> Datei erstellen, wenn Datei bereits existiert: unten anhängen

Danach kann mit dem normalen print-Befehl in die Datei geschrieben werden, es muss zwischen print-Befehl und Text lediglich noch der Dateihandler erwähnt werden. Das sieht dann so aus:

filewrite.cgi

#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<html><body>";

open(OUTPUTFILE,">test.txt") || die("FEHLER: Datei kann nicht geschrieben werden...");
print OUTPUTFILE "Zeile 1\n";
print OUTPUTFILE "Zeile 2\nZeile 3";
close(OUTPUTFILE);
print "Datei \"test.txt\" erfolgreich erstellt";
print "</body></html>";

oder auch filewrite2.cgi:

#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<html><body>";

if (open(OUTPUTFILE,">test.txt")) {
  print OUTPUTFILE "Zeile 1\n";
  print OUTPUTFILE "Zeile 2\nZeile 3";
  close(OUTPUTFILE);
  print "Datei \"test.txt\" erfolgreich erstellt";
} else {
  print "FEHLER: Datei kann nicht geschrieben werden...";
}
print "</body></html>";

Das ist jetzt aber wirklich einfach, oder?

Weitere Anmerkungen zu Dateien

Wenn eine Datei in ein Array eingelesen wird, wird sie immer beim Zeilenumbruch getrennt. Als Trennzeichen dient dabei die Systemvariable $/, welche standardmässig den - systemabhängigen - Zeilenumbruch enthält.

Ebenfalls stellt \n beim Schreiben in Dateien den systembedingten Zeilenumbruch dar, d.h. ein \n schreibt auf PC-Systemen ein \r\n in die Datei!

Wenn man die Datei im binär-Modus öffnet (egal ob zum lesen oder zum schreiben), werden systembedingte Zeilenumbrüche ignoriert. Dies geschieht mit dem Befehl binmode FILEHANDLE und sieht dann so aus:

open(FILE1,">test1.txt");
print FILE1 "Zeile1\nZeile2";
# Auf PC-Systemen enthält die Datei "Zeile1\r\nZeile2", Auf UNIX-Systemen "Zeile1\nZeile2"
close(FILE1);

open(FILE2,">test2.txt");
binmode FILE2;
print FILE2 "Zeile1\nZeile2";
# Auf PC- und UNIX-Systemen enthält die Datei "Zeile1\nZeile2"
close(FILE2);

Ebenfalls bewirkt ein binmode, dass beim Lesen von Dateien, die komplette Datei in eine Variable eingelesen wird:

open(FILE,"test.txt");
binmode FILE;
my $content = <FILE>;
close(FILE2);

Beispiel 1: Konfigurationsdateien

Dateien werden in der Praxis sehr häufig für Konfigurationsdateien verwendet. Nachfolgend nun zwei kleine Subroutinen, welche Konfigurationsdateien lesen und schreiben. Dabei wird die gesamte Konfiguration in den Hash %CONFIG eingelesen, bzw. der komplette Hash in die Konfigurationsdatei geschrieben. Die Konfigurationsdatei ist nach dem Schema Name=Wert aufgebaut.

# Config-File in %CONFIG einlesen; Aufruf: &readConfig("dateiname.cfg");
sub readConfig {
  my (@pair);
  if (-e $_[0]) {
    open(CONFIG,$_[0]);
    while (<CONFIG>) {
      chomp;
      (@pair) = split(/=/, $_, 2);
      $CONFIG{$pair[0]} = $pair[1] unless ($pair[0] eq "#!");
    }
    close(CONFIG);
  }
}

# Config-File aus %CONFIG schreiben, Aufruf: &writeConfig("dateiname.cfg");
sub writeConfig {
  open(CONFIG,">".$_[0]);
  foreach (sort keys(%CONFIG)) {
    print CONFIG "$_=$CONFIG{$_}\n";
  }
  close(CONFIG);
}

Beispiel 2: Virtuelles schwarzes Brett

Wenn Sie das komplette Tutorial durcharbeiten, haben Sie schon viel gelernt. Aus diesem Grund habe ich einmal ein kleines Script geschrieben, welches viel gelerntes einmal in einem praxisnahen Beispiel darstellt. Das Script ist ausführlich dokumentiert. Wenn etwas unklar ist, kann man im entsprechenden Kapitel des Tutorials nochmals nachschauen.

Das Script ist ein virtuelles schwarzes Brett, wo die Besucher ihre eigenen Kommentare, Anmerkungen etc. hinschreiben können, welche dann auch den anderen Besuchern zur Verfügung steht.

Natürlich wäre das Script noch verbesserungswürdig (z.B. Zeitpunkt des Eintrags, alte Einträge automatisch löschen etc.), aber als Beispiel reicht es völlig aus.

Hier geht's zum Beispiel 2: virtuelles schwarzes Brett. Natürlich können Sie auch mit dem Tutorial forrfahren.

Zusammenfassung

In diesem Beispiel haben wir Dateien gelesen und geschrieben, was unter Perl nicht sonderlich kompliziert ist. Wir wissen, dass wir mit > Dateien überschreiben und mit >> an eine bestehende Datei anhängen. Wir kennen ebenfalls "Datei Test Operationen", mit denen wir schon im Vorfeld prüfen können, ob wir eine Datei lesen oder schreiben dürfen. Zudem wissen wir, dass Zeilenumbrüche Systemabhängig sind und für UNIX-Zeilenumbrüche auf PC-Systemen in den Binär-Mode gewechselt werden muss.

Wie geht's weiter?

Kapitel 10 befasst sich mit dem Mailversand via Unix sendmail.

Das vorherige Kapitel (8) beschäftigte sich mit HTML-Formularen.

Sie können aber auch zurück zum Inhaltsverzeichnis und dort ein beliebiges anderes Kapitel auswählen.