Was bringt einem die beste Programmiersprache, wenn man keine Daten Speichern oder wieder Laden kann. Bevor
Sie nun aus einer
Datei lesen oder schreiben, müssen Sie diese erst mal öffnen. Hierzu verwenden
man das in C schon bekannte Schlüsselwort
open. Hier ist der Syntax von open ...
open(HANDLE, "modus $DATEINAME");
Hiermit öffnen Sie eine Datei Namens $DATEINAME mit dem Modus modus. Mit dem erzeugten Datei-HANDLE können
Sie anschließend die Datei weiterverarbeiten. Folgende Modis stehen Ihnen für das öffnen
einer Datei zur Verfügung ...
- open(HANDLE, "datei"); Datei zum Lesen öffnen
- open(HANDLE, "< datei"); Datei zum Lesen öffnen, existiert diese nicht scheitert die Funkion
- open(HANDLE, "+< datei"); Datei zum Lesen und Schreiben öffnen
- open(HANDLE, "> datei"); Datei zum Schreiben öffnen, falls nicht vorhanden wird diese erzeugt
- open(HANDLE, ">> datei"); Datei öffnen zum Anhängen, falls nicht vorhanden wird diese erzeugt
Sollte das öffnen einer Datei fehlschlagen, müssen Sie nicht wie in anderen Programmiersprachen den Rückgabewert der Funktion überprüfen sondern lediglich eine
or-Verknüpfung mit der Funktion 'die' machen ...
open(HANDLE, "< $file")
or
die "\nKonnte Datei $file nicht zum Lesen öffnen\n";
Mit dem folgendem Skript können Sie aus einer Datei lesen ...
#!/usr/bin/perl -w
print "Welche Datei wollen Sie zum Lesen öffenen : " ;
chomp ( $file=<>);
open(FH, "< $file")
or
die "\nKonnte die Datei $file nicht zum Lesen öffnen\n";
while($zeile=<FH>){
if($. %10){ #Alle 10 Zeilen anhalten
print $zeile;
}
else{
print "Für weiteren Text bitte drücken\n";
<STDIN>;
}
}
close(FH);
Mit diesem einfachen Beispiel öffnen Sie die Datei $file, falls vorhanden und geben den Text
in Zehn-Zeilenweise aus.
Wichtig ist übrigens auch das schließen eines Datei-Handle mit close. Dies versichert, dass eventuell sich noch im Puffer befindlichen Dateien geschrieben und Abgeschlossen werden.
Vorraussetzung das Sie Dateien öffnen können, ist übrigens auch der richtige Pfadnamen und der komplette Dateiname mit Endung.
Eine weitere Möglichkeit eine Datei zu öffnen ist die Kommandozeile ...
#!/usr/bin/perl -w
$counter=0;
$file="null";
foreach (@ARGV){
$counter++;
if($counter > 1){ #Wurde mehr als 1 Argument angegeben
print "\nProgramm bitte nur mit 1 Argument starten\n";
last;
}
$file=$_;
}
if($file eq "null" ){ #wurden überhaupt Argumente mit angegeben
die "\nProgrammaufruf : programm file \n";
}
elsif($file eq "-h" or $file eq "-help"){
die "\nSie haben den help-Schalter aufgerufen\n";
}
open(FH, "< $file")
or
die "\nKonnte die Datei $file nicht zum Lesen öffnen\n";
while($zeile=<FH>){
if($. %10){ #Alle 10 Zeilen anhalten
print $zeile;
}
else{
print "Für weiteren Text bitte drücken\n";
<STDIN>;
}
}
close(FH);
Hier haben Sie ein kleines Beispiel wie Sie die Kommandozeile mit der Standardvariablen
@ARGV auswerten können.
Jetzt fehlt eigentlich nur noch die Möglichkeit, in einer Datei etwas zu Schreiben. Dabei wird es einem recht einfach gemacht in Perl ...
#!/usr/bin/perl -w
print "Welche Datei wollen Sie zum Anhängen öffnen : ";
chomp( $file = <>);
open(FH, ">> $file")
or
die "\nKonnte die Datei $file nicht zum Anhängen öffnen\n";
print ">";
$\ = "\n"; #Ausgabe mit mit \n beenden
$zeile=<STDIN>; #Eingabe von STDIN
print FH $zeile; #Eingabe in die geöffnete Datei $file schreiben
close(FH);
Hier benutzen Sie lediglich die print-Anweisung und stellen nur den File-Handle davor.
Dies funktioniert natürlich auch mit printf. Die default-Einstellung von print und printf lautet ja ...
print STDOUT $variable;
printf STDOUT "$variable";
Sie benutzen bisher immer die kürzere Schreibweise da es ja die default-Einstellung ist.
Somit sind Sie nun in der Lage, Dateien zu kopieren. Das folgend Programm dürfte nun kein Problem mehr für
Sie sein ...
#!/usr/bin/perl -w
print "Welche Datei wollen Sie Kopieren : ";
chomp ($quelle = <>);
print "Wie soll die Kopie heißen : ";
chomp( $ziel = <>);
open(FHquelle, "< $quelle")
or
die "\nKonnte die Datei $quelle nicht zum Lesen öffen\n";
open(FHziel, "> $ziel")
or
die "\n Konnte die Datei $ziel nicht zum Schreiben öffnen bzw. erzeugen\n";
while($zeile = <FHquelle>){ #Lesen aus der Quelle
print FHziel $zeile; } #Schreiben ins Ziel
close(FHquelle);
close(FHziel);
Eine weitere Interessante Möglichkeit zum Öffnen von Dateien, stellt das
Öffnen und Lesen aus laufenden Programmen da. Für open gelten in diesem Falls folgende Regeln ...
- der Filehandle unterscheidet sich nicht zu den Beispielen vorher
- der 2.Parameter ist der Formatstring mit dem Namen des zu startenden Programms. WICHTIG -> Am Ende des Formatstrings müssen
Sie das Zeichen | einfügen ...
open(FH, "less $datei |") or die ".....";
open(FH, "ps -x |") or die "......";
Nun können Sie mit einem so geöffneten Programm, lesend auf die Ausgabe zurückgreifen. Das sich damit eine Unmenge an
Flexibilität ergibt ist klar. Natürlich können Sie auch mehrere Programme mit Hilfe der Pipe auf einmal ausführen ...
open(FH, "less $datei | cpio -o | gzip -9 |") or die "...";
Der Nachteil an dieser Methode ist, der Rückgabewert von open() kann nicht Zuverlässig überprüft werden, da
popen() (Pipe) diese Methode ermöglicht.
Sie können als Beispiel die PID unseres eigenem Programms mit Hilfe von ps ausgeben lassen ...
#!/usr/bin/perl -w
#Linux/Unix only
$pid = $$;
open(FH, "ps -x |")
or die "Kein solche Datei vorhanden...\n";
while($tmp=<FH>){
if($tmp =~ m/$pid/){
print $0 , " : " , $tmp , "\n";
}
}
Langsam können Sie erkennen, wie mächtig aber simpel diese Methode ist. C-Programmierer unter Linux/Unix, kennen dies unter der Funktion
popen(). Nun wird das Programm von oben verbessert und alle Prozesse die mit der Tastenkombination STRG+Z gestoppt wurden
und alle Zombieprozesse, sollen gekillt (beendet) werden ...
#!/usr/bin/perl -w
#Linux/Unix only und geeignete Zugriffsrechte müssen vorhanden sein
open(FH, "ps -x |")
or die "Kein solche Datei vorhanden...\n";
while($tmp=<FH>){
if(($pid) =$tmp =~ m/(\d{4})/){ #Anpassen 4=Länge der PID!
if($tmp =~ m/(\sT\s|\sZ\s)/){ #T=gestoppt Z=Zombie
print $pid , " : " , $tmp , "\n";
system("kill -9 $pid"); #killen
}
}
}
Das Programm soll allerdings keine Schule machen, sondern dient nur zur Demonstration.
Anders herum ist es in Perl ebenso möglich, mit open() Programme von der Standardeingabe zu füllen.
Das Prinzip ist das selbe wie schon im Kapitel zuvor, nur das die Pipe (|) am Anfang des Strings steht ...
open(FH, "| programmname > $outfile") or die ".......";
Dies eignet sich zum Beispiel hervorragend, um aus einem Programm heraus, mittels
sendmail ein Mail zu verschicken ...
#!/usr/bin/perl -w
open(WHERE, "which sendmail |") or die "Kein sendmail gefunden ...\n";
chomp($sendmail = <WHERE>);
close(WHERE);
$to = "root\@localhost.localdomain\n"; #Bitte anpassen
open(MAIL, "| $sendmail -oi -t $to")
or die "Can't open pipe to $sendmail: $!\n";
print MAIL "From: Bill.Gates\@microsoft.com\n";
print MAIL "Subject: Hallo Pinguin\n\n";
print MAIL "Dies stellt den Inhalt der Mail da\n";
close(MAIL) or die "Can't close pipe to $sendmail: $!\n";
print "Die Mail wurde erfolgreich verschickt\n";
Und schon haben Sie eine Fake-Mail verschickt. Das Programm funktioniert natürlich nur wenn sich auf Ihrem Rechner
auch das Programm sendmail befindet und dies entsprechend konfiguriert ist.
Viele werden bei diesem Beispiel an die CGI-Programmierung denken. Und dabei haben
Sie recht. Diese Beispiel werden Sie später in ähnlicher Weise bei der CGI-Programmierung, zum Verschicken einer Formmail, verwenden.
ABSATZWEISE:
#!/usr/bin/perl -w
{
local $/ = ''; #Absatzmodus
while(<>){ #Absatz in $_
print;
print "\t\t\tABSATZ - weiter mit +\n";
<STDIN>;
}
}
KOMPLETT EINLESEN:
#!/usr/bin/perl -w
{
local undef $/; #Slurp mode
while(<>){ #Kompletter Inhalt in $_
print;
}
}
SATZWEISE:
#!/usr/bin/perl -w
{
local $/="."; #Satztrennzeichen '.' -> Bitte Anpassen!
while(<>){
print;
<STDIN>; #Weiter mit STRG+D
}
}
Bei diesem Beispiel ist man besser mit einer Pattern-Matching-Operation beraten.
BESTIMMTE ZEILE:
#!/usr/bin/perl -w
{
local $/ = "\n";
$suchzeilennr=50;
while(<>){
print $. ,":" , $_ if $. == $suchzeilennr;
}
}
ZEILENWEISE LESEN:
#!/usr/bin/perl -w
{
local $/ = "\n";
while(<>){
print $. ,":" , $_;
}
}
WORTWEISE LESEN:
#!/usr/bin/perl -w
undef $/; #Slurp mode
$_=<>; #alles in $_
@worte=split(m/\s/, $_); #Aufspliten durch Whitespace-Zeichen
print "@worte";
print "\n\nElemente im Array : " , $#worte+1 , "\n";
NACH DATEIENDUNGEN SUCHEN:
#!/usr/bin/perl -w
@file = <*>; #keine Files die mit einem '.' beginnen...
@file2= <.*>; #Alle versteckten Files die mit einem '.' beginnen...
@file3= <*.c>; #Alle C-Files (z.B. test.c)
@file4= <* .* *.c>; #Alle zusammen.....
@file5= <*.txt>; #alle Textdateien
print join(' ', @file) , "\n\n";
print join(' ', @file2) , "\n\n";
print join(' ', @file3) , "\n\n";
print join(' ', @file4) , "\n\n";
print join(' ', @file5) , "\n\n";
DATEIENDUNG ÄNDERN :
#!/usr/bin/perl -w
#Dateiendung verändern aus *.c wird *.c.bak
foreach $rename(<*.c>){
rename($rename, "$rename".".bak") or warn("Fehler bei rename....\n");
}
DATEIENDUNG WIEDER RÜCKGÄNGIG MACHEN:
#!/usr/bin/perl -w
#Dateiendung verändern aus *.c.bak wird *.c
foreach $rename(<*.bak>){
$temp=$rename;
$temp=~s/\.bak$//;
rename("$rename", "$temp");
}
Um einen Filehandle aus einer Funktion zurückzugeben, müssen
Sie einen
Wrapper schreiben. Ein Wrapper ist ein Strumpf den man der Hauptfunktion überzieht.
Folgendes Beispiel zeigt es, wie Sie dies in Perl bewerkstelligen können ...
#!/usr/bin/perl -w
sub Open{
my $pfad=$_[0];
local *FH;
open(FH, $pfad) or die $!;
return *FH;
}
*FH_READ=Open("/usr/include/stdio.h");
while(<FH_READ>){
print;
}
Hier wird die Wrapper-Funktion immer mit dem selben Namen verwendet. Nur den Anfangsbuchstaben
wird dabei Großgeschrieben, um diese Funktion von der echten Funktion zu unterscheiden
(a la Richard W. Stevens).
Wofür steht das Sternchen am Anfang des Filehandle? Testen Sie am besten folgendes Beispiel ...
#!/usr/bin/perl -w
*var1=5;
*var2="hallo";
print *var1 , ":" , *var2 , "\n";
Anhand der Aussage dürfte nun schon einiges klar sein. Das Sternchen ist nicht speziell für Filehandles reserviert, sondern kann bei allen möglichen Variablen verwendet werden. Also kann man sich das Sternchen als ein Art Wildcard für eine Variable vorstellen, die
sowohl für $, @ und % steht. Aber auch für eine Filehandle, der kein Präfix
besitzt.
Man kann es sich aber auch einfacher merken, wenn man sagt, das Sternchen ist das Präfix für einen
Filehandle, auch wenn es nicht ganz richtig ist.
Bei der Übergabe als Funktionsparameter funktioniert das Ganze ähnlich ...
#!/usr/bin/perl -w
sub Read{
local *FH=shift;
while(<FH>){print;}
}
open(FH_READ,"/usr/include/stdio.h") or die $!;
Read(*FH_READ);
sysopen und open unterscheiden sich Hauptsächlich dadurch, dass mit sysopen die Zugriffsrechte und der Öffnungsmodus genau festgelegt werden können. Hier ein Beispiel zu
sysopen ...
#!/usr/bin/perl -w
use Fcntl;
sysopen(FH, "./Neuedatei.txt", O_WRONLY|O_CREAT, 0600) or die $!;
print FH "Dieser Text wird in Neuedatei.txt geschrieben\n";
close(FH);
Anhand diese Beispiels können Sie erkennen, dass die Unterschiede zu open nicht allzu groß sind. Der Filehandle ist der selbe. Bei der Dateiangabe benötigen
Sie nicht mehr die Zeichen <,>,+< usw. da Sie dies mit den O_*-Konstanten
machen (welche das Modul Fcntl benötigen). Bei diesem Beispiel eben erzeugen
Sie eine Datei (O_CREAT) ausschließlich zum Schreiben (O_WRONLY) mit den Zugriffsrechten 0600. Also nur für den Eigentümer. Also nochmals der Syntax zu sysopen ...
sysopen(Filehandle,Dateiname,Öffnungsmodus,Zugriffsrechte);
Weitere Zugriffsarten zu sysopen lauten ...
| Modus |
Bedeutung |
| O_RDONLY |
nur
zum lesen öffnen (O_RDONLY=0) |
| O_WRONLY |
nur
zum schreiben öffnen (O_WRONLY=1) |
| O_RDWR |
zum
lesen und schreiben öffnen (O_RDWR=3) |
| O_CREAT |
Falls
Datei nicht existiert wird Sie neu angelegt. Falls die Datei existiert
wird ist O_CREAT ohne Wirkung. |
| O_APPEND |
Datei
zu Schreiben am Ende "Anhängen". |
| O_EXCL |
O_EXCL
kombiniert mit O_CREAT bedeutet das die Datei nicht geöffnet werden
kann wenn Sie bereits existiert und open den Wert -1 zurückliefert. (-1
== Fehler) |
| O_TRUNC |
Eine
Datei die zum Schreiben geöffnet wird wird geleert. Das Nachfolgende
Schreiben bewirkt erneutes Beschreiben der Datei von Anfang an. Die
Attribute der Datei bleiben erhalten. |
| O_NOCTTY |
Falls
der Pfadname der Name eines Terminal ist, so sollte dies nicht der
Kontrollterminal des Prozesses werden. |
| O_NONBLOCK |
Falls
der Pfadname der Name einer FIFO oder Gerätedatei ist, wird diese beim
Öffnen und bei nachfolgenden I/O- Operationen nicht blockiert. |
| O_SYNC |
Nach
dem Schreiben mit write warten, daß der Schreibvorgang vollständig
abgeschlossen ist. |
Mit der Funktion sysread können Sie von einem Filehandle lesen. Außerdem liest sysread die Daten Ungepuffert ein.
Auch hierzu wieder ein kurzes Skript ...
#!/usr/bin/perl -w
use Fcntl;
sysopen(FH, "./Neuedatei.txt", O_RDONLY) or die $!;
$bytes=sysread(FH, $buffer,50);
print $buffer , "\n" if $bytes == 50;
close(FH);
Nun die Erklärung zu ...
$bytes=sysread(FH, $buffer,50);
Hiermit ließt man von der Datei mit dem Filehandle FH, 50 Bytes in den Puffer
$buffer ein. Den Rückgabewert überprüfen Sie ebenso, ob auch wirklich 50 Zeichen an
$buffer übergeben wurden.
Der Vorteil liegt auch hier wieder ganz klar bei der Performance. sysread ist bei größeren Datenmengen schneller als zum Beispiel read oder alle anderen gepufferten
Einlesearten.
Das Gegenstück zu sysread ist syswrite. Auch hiermit können wir wieder ungepuffert in eine Datei schreiben. Die Anwendung von syswrite ist die selbe wie von
sysread...
#!/usr/bin/perl -w
use Fcntl;
sysopen(FH, "./Neuedatei.txt", O_RDONLY) or die $!;
sysopen(BAK,"./backup.bak", O_WRONLY|O_CREAT, 0600) or die $!;
$bytes_rd=sysread(FH, $buffer,50);
$bytes_wr=syswrite(BAK, $buffer,50) if $bytes_rd == 50;
print "Fehler beim Schreiben in backup.bak\n" if $bytes_wr != 50;
close(FH);
close(BAK);
Hier wird eine Kopie von Neuedatei.txt angelegt, die Sie zuvor mit sysread auslesen. Anschließend schreiben
Sie die im $buffer ausgelesenen Zeichen, in den Filehandle BAK (wieder 50 Bytes).
Sie sollten bei den sys...-Aufrufen jedoch beachten, dass Sie diese nicht mit Funktionen der Standard-Bibliothek vermischen, wegen der Unterschiedlichen Pufferung. Mit Nicht-Vermischen sind die Funktionen sysread, syswrite, systell, sysseek gemeint. Diese sollten nicht mit read, seek, tell....usw. verwendet werden.
|