ppt

Werbung
Programmierkurs für absolute Anfänger
 Dateihandles, formatierte Ausgabe, Subroutinen
Caren Brinckmann
Sommersemester 2005
http://www.coli.uni-saarland.de/~cabr/teaching.php
Dateihandles




Um in Perl eine bestimmte Datei zum Lesen, Schreiben oder
Anhängen zu öffnen, benötigt man so genannte Dateihandles.
Ein Dateihandle ist der Name einer Eingabe-/Ausgabe-Verbindung
zwischen dem Perl-Programm und der "Außenwelt".
Dateihandles sollten komplett in Großbuchstaben geschrieben
werden, damit sie nicht mit Funktionsnamen verwechselt werden
können.
Sechs Dateihandle-Namen sind bereits von Perl mit einer Bedeutung
belegt (und sollten daher nicht für einen anderen Zweck benutzt
werden):
STDIN: Standardeingabe (normalerweise: Tastatur)
STDOUT: Standardausgabe (normalerweise: Bildschirm)
STDERR: Standardfehlerausgabe (normalerweise: Bildschirm)
außerdem: ARGV, ARGVOUT, DATA
Programmierkurs für absolute Anfänger – Sitzung 11
1
STDIN, STDOUT und STDERR

Ein Perlprogramm liest normalerweise von STDIN und schreibt nach
STDOUT (Funktion print). Fehlermeldungen (Funktion die) und
Warnhinweise werden nach STDERR geschrieben.

Normalerweise stellt STDIN eine Verbindung zwischen dem
Perlprogramm und der Tastatur her, STDOUT und STDERR verbinden
das Programm mit dem Bildschirm.

Beim Programmaufruf kann man aber dafür sorgen, dass das
Perlprogramm seine Eingabedaten aus einer Datei liest, seine
Ausgabedaten in eine andere Datei schreibt, und die
Fehlermeldungen an eine dritte Datei anhängt:
perl -w meins.pl < rein.txt > raus.txt 2>> fehler.txt
Programmierkurs für absolute Anfänger – Sitzung 11
2
Dateihandles öffnen: open

Mit dem Operator open wird Perl angewiesen, eine
Verbindung zwischen dem Programm und der
Außenwelt (meistens: einer Datei) herzustellen.

Dabei wird unterschieden, ob die entsprechende Datei
zum Lesen, Schreiben oder Anhängen geöffnet wird:
open(KIELDATEI, "<kkos025.s1h"); ## lesen
open(AUSGABE, ">label.txt");
## schreiben
open(LOGDATEI, ">>log.txt");
## anhängen

Anstelle des Dateinamens kann eine skalare Variable
verwendet werden, z.B.:
$ausgabedatei = $ARGV[0];
open(AUSGABE, ">$ausgabedatei");
Programmierkurs für absolute Anfänger – Sitzung 11
3
Schlechte Dateihandles




Wenn die Rechte der zu öffnenden Datei nicht korrekt gesetzt sind, ein
falscher Dateiname angegeben wird oder andere Gründe gegen ein
Öffnen sprechen, kann das Betriebssystem den Zugriff auf die Datei
verweigern.
Beim Versuch, von einem solchen schlechten Dateihandle zu lesen,
wird undef bzw. die leere Liste zurückgegeben (je nach Kontext).
Beim Versuch, in ein schlechtes Dateihandle zu schreiben, werden die
Daten stillschweigend verworfen!
Daher sollte immer überprüft werden, ob der Aufruf von open
erfolgreich war. Ggf. wird das Programm mit einer entsprechenden
Fehlermeldung abgebrochen:
open(AUSGABE, ">$ausgabedatei") or die "Konnte
Ausgabedatei $ausgabedatei nicht oeffnen: $!\n";
Programmierkurs für absolute Anfänger – Sitzung 11
4
Spezialvariable $!



Nach einem fehlgeschlagenen Aufruf des Betriebssystems (z.B. durch
den Versuch, eine Datei zu öffnen, für die der Benutzer keine
Zugriffsrechte hat) enthält die Spezialvariable $! die Fehlermeldung
des Betriebssystems, z.B. "Permission denied".
Wird nach $! kein Zeilentrennzeichen \n eingefügt, so wird an das
Ende der Meldung automatisch der Name des Perl-Programms und
die Zeilennummer angehängt. Dies hilft bei der systematischen
Fehlersuche.
Beispiel:
open(AUSGABE, ">$ausgabedatei") or die "Konnte
Ausgabedatei $ausgabedatei nicht oeffnen: $!";
erzeugt z.B. folgende Fehlermeldung:
Konnte Ausgabedatei test.txt nicht oeffnen:
Permission denied at meinprogramm.pl line 4.
Programmierkurs für absolute Anfänger – Sitzung 11
5
Dateihandles benutzen

Wenn ein Dateihandle zum Lesen geöffnet ist, können
die Zeilen genauso gelesen werden, als kämen sie von
STDIN:
open(KIELDATEI, "<$datei") or die "Konnte die
Datei $datei nicht oeffnen: $!";
@zeilen = <KIELDATEI>;
chomp(@zeilen);

Standardverhalten von print: Ausgabe auf STDOUT.
print kann aber auch mit einem Dateihandle als
Argument aufgerufen werden, so dass die Ausgabe in
die entsprechende Datei erfolgt:
print LOGDATEI "Datei $datei bearbeitet.\n";
Programmierkurs für absolute Anfänger – Sitzung 11
6
Standarddateihandle für
Ausgaben ändern: select

print gibt die Daten standardmäßig nach STDOUT aus.

Der Operator select setzt das Standarddateihandle für
Ausgaben (mit print) auf das angegebene Dateihandle:
open(AUSGABE, ">$ausgabedatei") or die "Konnte
Ausgabedatei $ausgabedatei nicht oeffnen: $!";
select AUSGABE;
print "Label: $label\tDauer: $dauer[$label]\n";
print "Ergebnis: $ergebnis\n";

Das mit select ausgewählte Standarddateihandle gilt
bis zum Ende des Programms – oder bis es auf ein
anderes Dateihandle gesetzt wird.
Programmierkurs für absolute Anfänger – Sitzung 11
7
Dateihandles schließen: close

Der Operator close schließt das angegebene
Dateihandle und gibt die entsprechenden
Systemressourcen wieder frei.

Daher ist es guter Programmierstil, jedes geöffnete
Dateihandle wieder zu schließen, sobald es nicht mehr
gebraucht wird:
open(KIELDATEI, "<$datei") or die "Konnte die
Datei $datei nicht oeffnen: $!";
@zeilen = <KIELDATEI>;
chomp(@zeilen);
close KIELDATEI;
Programmierkurs für absolute Anfänger – Sitzung 11
8
Dateigröße abfragen

Wenn eine Datei existiert und nicht leer ist, kann man
ihre Größe (in Bytes) mit dem Dateitest -s abfragen:
$datei = "test.txt";
$dateigroesse = -s $datei;
print "Die Datei $datei ist $dateigroesse
Bytes groß.\n";

weitere Dateitests:
http://perldoc.perl.org/functions/-X.html
Programmierkurs für absolute Anfänger – Sitzung 11
9
Verzeichnishandles


Wenn mehrere Dateien aus einem Verzeichnis gelesen
werden sollen, so muss zunächst eine Liste der
Dateinamen erzeugt werden. Dazu kann man ein
Verzeichnishandle benutzen.
Ein Verzeichnishandle sieht aus wie ein Dateihandle und
verhält sich auch so:



opendir öffnet ein Verzeichnishandle
readdir liefert den nächsten Dateinamen aus dem Verzeichnis
(skalarer Kontext) bzw. die Liste aller restlichen Dateinamen
(Listenkontext)
Achtung: Die Dateinamen enthalten nicht den Verzeichnisnamen!
closedir schließt das Verzeichnishandle
Programmierkurs für absolute Anfänger – Sitzung 11
10
Beispiel: Verzeichnishandles
$verzeichnis = "/proj/PhonDat/Data/Read";
opendir(KIELVERZ, $verzeichnis) or die "Konnte
Verzeichnis $verzeichnis nicht oeffnen: $!";
while ($dateiname = readdir KIELVERZ) {
if ($dateiname =~ /\.s1h$/) {
$dateiname = "$verzeichnis/$dateiname";
open(KIELDATEI, "<$dateiname") or die "Konnte
Datei $dateiname nicht oeffnen: $!";
## ...
close KIELDATEI;
}
}
closedir(KIELVERZ);
Programmierkurs für absolute Anfänger – Sitzung 11
11
Formatierte Ausgabe: printf (1)


Der Operator printf nimmt eine Formatierungszeichenkette, die das
Format angibt, gefolgt von der Liste der Dinge, die ausgegeben
werden sollen, und gibt diese auf STDOUT (oder einem anderen
Dateihandle) aus.
Die Formatierungszeichenkette enthält eine Reihe so genannter
Konversionen:
Jede Konversion beginnt mit einem Prozentzeichen und endet mit einem
Buchstaben.
 Die Liste, die auf die Formatierungszeichenkette folgt, sollte immer
genausoviele Elemente enthalten, wie es Konversionen gibt.
printf "Das Passwort von %s ist noch %d Tage gültig!\n",
$name, $gueltig;


Die gebräuchlichsten Konversionen sind:



%s
%d
%f
eine Zeichenkette
eine ganze Zahl
eine Kommazahl (mit Punkt statt Komma)
Programmierkurs für absolute Anfänger – Sitzung 11
12
Formatierte Ausgabe: printf (2)

printf wird häufig dafür verwendet, Daten spaltenweise
auszugeben, da für die meisten Konversionen eine Feldbreite
angegeben werden kann.

Beispiel: Zahlen rechtsbündig ausgeben (Spaltenbreite: 8 Zeichen)
@zahlen = (23, 123778, -450);
foreach $zahl (@zahlen) {
printf "%8d\n", $zahl;
}
erzeugt folgende Ausgabe:
23
123778
-450

Ein negativer Wert für die Feldbreite führt zu einer linksbündigen
Ausgabe.
Programmierkurs für absolute Anfänger – Sitzung 11
13
Formatierte Ausgabe: printf (3)

Mit der %f-Konversion kann man Kommazahlen runden:
printf "%.3f\n", 6 * 7 + 2/3;
printf "%.0f\n", 6 * 7 + 2/3;
erzeugt folgende Ausgabe:
42.667
43

Kombination von Feldbreite und Rundung:
printf "%8.3f\n", 6 * 7 + 2/3;
printf "%8.0f\n", 6 * 7 + 2/3;
erzeugt folgende Ausgabe:
42.667
43

Um ein Prozentzeichen auszugeben, muss %% verwendet werden:
printf "Monatlicher Zinssatz: %.2f%%\n", 5.25/12;
Programmierkurs für absolute Anfänger – Sitzung 11
14
Daten formatieren: sprintf

sprintf nimmt die gleichen Argumente wie printf
(abgesehen von dem optionalen Dateihandle).

Die jeweilige Zeichenkette wird jedoch nicht
ausgegeben, sondern als Rückgabewert
zurückgegeben, der in einer skalaren Variablen
gespeichert werden kann:
$dauer = sprintf "%.0f", $dauer;
Programmierkurs für absolute Anfänger – Sitzung 11
15
Subroutinen

Wir kennen bereits diverse in Perl eingebaute Funktionen: chomp,
reverse, die, pop, shift usw.

Vom Programmierer selbst definierte Funktionen nennt man
Subroutinen. Hierdurch kann man denselben Anweisungsblock in
einem Programm mehrmals verwenden.
Subroutinen können an jeder beliebigen Stelle im Programm
definiert werden (Standard: entweder alle am Anfang oder alle am
Ende).
Subroutinen-Definitionen sind global, d.h. sie gelten im gesamten
Programm.
Achtung: Werden in einem Programm zwei Subroutinen mit dem
gleichen Namen definiert, so überschreibt die später definierte die
frühere!



Programmierkurs für absolute Anfänger – Sitzung 11
16
Subroutinen: Definition und Aufruf


Um eine Subroutine zu definieren, benutzt man das Schlüsselwort
sub, gefolgt vom Namen der Subroutine und dem Anweisungsblock
(in geschweiften Klammern):
sub marine {
$n += 1; ## globale Variable $n
print "Hallo, Taucher Nummer $n!\n";
}
Um eine Subroutine innerhalb des Programms aufzurufen,
verwendet man einfach ihren Namen, dem ein & vorangestellt wird:
$n = 0;
&marine;
&marine;
&marine;
&marine;
Programmierkurs für absolute Anfänger – Sitzung 11
17
Subroutinen: Rückgabewerte (1)


Oft ist es so, dass man beim Aufruf einer Subroutine das Ergebnis
einer Berechnung in der Subroutine verwenden will, den so genannten
Rückgabewert der Subroutine.
In Perl haben alle Subroutinen automatisch einen Rückgabewert,
nämlich den Wert des Ausdrucks, der zuletzt ausgewertet wird:
sub summe_x_y {
print "Aufruf der Subroutine summe_x_y\n";
$x + $y; # Dies ist der Rückgabewert.
}
$x = 3;
$y = 4;
$z = &summe_x_y;
print "\$z hat den Wert $z.\n";
$k = 3 * &summe_x_y;
print "\$k hat den Wert $k.\n";
Programmierkurs für absolute Anfänger – Sitzung 11
18
Subroutinen: Rückgabewerte (2)

Achtung: Wenn die beiden Anweisungen in der Subroutine
summe_x_y vertauscht werden, ist der Rückgabewert der
Rückgabewert von print (normalerweise: 1)!
sub summe_x_y {
$x + $y;
print "Aufruf der Subroutine summe_x_y\n";
}

Wichtig: Der "letzte ausgewertete Ausdruck" ist nicht unbedingt
identisch mit der letzten Zeile Text in der Subroutine:
sub max_x_y {
if ($x > $y) {
$x;
} else {
$y;
}
}
Programmierkurs für absolute Anfänger – Sitzung 11
19
Subroutinen: Rückgabewerte (3)

Wird eine Subroutine im Listenkontext aufgerufen, so kann sie
auch eine Liste von Werten zurückgeben:
sub liste_von_x_bis_y {
if ($x < $y) {
$x..$y;
} else {
reverse $y..$x;
}
}
$x = 11;
$y = 6;
@z = &liste_von_x_bis_y;
print "@z";
Programmierkurs für absolute Anfänger – Sitzung 11
20
Subroutinen: Operator return

Der Operator return beendet die Subroutine sofort und
gibt das bei seinem Aufruf angegebene Argument zurück,
z.B.: return $x + $y;

Wird return ohne ein Argument benutzt, so wird ein
leerer Wert zurückgegeben, also


im skalaren Kontext: undef

im Listenkontext: die leere Liste
Guter Programmierstil: return jedesmal benutzen, wenn
es einen sinnvollen Rückgabewert gibt.
Programmierkurs für absolute Anfänger – Sitzung 11
21
Subroutinen: Argumente (1)

In den bisherigen Beispielen wurden in den Subroutinen globale
Variablen verwendet, d.h. Variablen, die von jedem Teil des
Programms aus zugänglich und veränderbar sind. Z.B. hat die
Subroutine max_x_y als Rückgabewert das Maximum der beiden
globalen Variablen $x und $y:
sub max_x_y {
if ($x > $y) {
return $x;
} else {
return $y;
}
}

Viel praktischer ist es jedoch, die Subroutine bei jedem Aufruf mit
neuen Werten – so genannten Argumenten – aufrufen zu können,
ohne sich auf die globalen Variablen $x und $y verlassen zu
müssen.
Programmierkurs für absolute Anfänger – Sitzung 11
22
Subroutinen: Argumente (2)

Um eine Liste von Argumenten an eine Subroutine zu übergeben,
werden diese einfach in runden Klammern hin der Aufruf der
Subroutine geschrieben:
$n = &max(10, 15);

Für die Dauer der Subroutine enthält die spezielle Arrayvariable @_
die Liste der aufrufenden Argumente.

Im obigen Beispiel enthält beim Aufruf der Subroutine max also
$_[0] den Wert 10, $_[1] enthält den Wert 15. Diese Werte kann
die Subroutine max dann verwenden.

Die Variable @_ existiert in der Subroutine lokal, d.h. wenn es auch
eine globale Variable @_ gibt, so wird deren Wert vor dem Aufruf
der Subroutine gesichert und nach Beendung der Subroutine
wieder hergestellt. Bei verschachtelten Subroutinen-Aufrufen
bekommt so jede Subroutine ihr eigenes @_-Array zugeteilt.
Programmierkurs für absolute Anfänger – Sitzung 11
23
Private Variablen (1)


Standardmäßig sind alle Variablen in einem Perl-Programm als
globale Variablen angelegt, d.h. sie sind von jedem Teil des
Programms aus zugänglich und veränderbar.
Mit dem Operator my können aber private bzw. lexikalische Variablen
angelegt werden:
sub max {
my ($x, $y) = @_;
if ($x > $y) { return $x; } else { return $y; }
}

Private Variablen gelten nur innerhalb des sie umschließenden
Anweisungsblocks:



Andere Variablen außerhalb des Blocks, die auch $x und $y heißen,
werden nicht beeinflusst.
Ebenso können die privaten Variablen nicht versehentlich von außen
verändert werden.
Die obige Subroutine max kann also in ein beliebiges Perl-Programm
eingebaut werden, ohne andere Variablen in dem Programm, die zufällig
auch $x und $y heißen, zu verändern.
Programmierkurs für absolute Anfänger – Sitzung 11
24
Private Variablen (2)

Private Variablen können in jedem beliebigen Anweisungsblock
verwendet werden, z.B. in einem if-Block oder in Schleifen mit for
oder while:
@zahlen = 2..5;
for (my $i=0; $i <= $#zahlen; $i++) {
my $quadrat = $zahlen[$i] ** 2;
print "$zahlen[$i] zum Quadrat ist $quadrat.\n";
}
print "\$i hat den Wert $i.\n";

Mit my lassen sich auch neue private Arrays oder Hashes anlegen:
my @zahlenliste;
my %telefonnummer;

Neu angelegte Variablen sind zu Beginn immer leer (es sei denn, sie
werden mit einem bestimmten Wert initialisiert), d.h. undef für skalare
Variablen und die leere Liste für Arrays und Hashes.
Programmierkurs für absolute Anfänger – Sitzung 11
25
Private Variablen (3)
Achtung: Der Operator my verändert den Kontext
einer Zuweisung nicht!

skalarer Kontext:
my $num = @_;
 $num enthält als Wert die Anzahl der Elemente in @_

Listenkontext:
my ($num) = @_;
 $num enthält als Wert das erste Element von @_
Programmierkurs für absolute Anfänger – Sitzung 11
26
Pragma "use strict"

Ein Pragma ist eine Anweisung an den Compiler, wie das Programm
kompiliert werden soll. Diese Anweisung wird an den Anfang des
Programms geschrieben.

Das Pragma use strict teilt dem internen Perl-Compiler mit, dass
innerhalb des Programms einige gute Programmierregeln beachtet
werden müssen, u.a. dass jede Variable mit my deklariert werden
muss.

Ausnahme: Die in Perl eingebauten Variablen wie z.B. $_, @_, $!,
@ARGV, $a und $b (bei sort) und werden niemals extra mit my
deklariert.

Damit gibt es schon eine Fehlermeldung zur Compile-Zeit, wenn z.B.
eine Variable aus Versehen falsch geschrieben wurde.

Regel: Bei jedem Programm, das mehr als 20 Zeilen lang ist, use
strict verwenden und alle Variablen mit my deklarieren!
Programmierkurs für absolute Anfänger – Sitzung 11
27
Beispiel: use strict
use strict;
my @woerter = <STDIN>;
chomp (@woerter);
## ... weitere Anweisungen
if ($wort[0] eq "hend") {
## ... weitere Anweisungen
}
 Fehlermeldung zur Compile-Zeit, da keine Arrayvariable mit dem
Namen @wort deklariert wurde. Das Programm wird nicht ausgeführt.
Global symbol "@wort" requires explicit package name
at stricttest.pl line 5.
Execution of stricttest.pl aborted due to compilation
errors.
Programmierkurs für absolute Anfänger – Sitzung 11
28
Argumentlisten mit variabler Länge

Innerhalb einer Subroutine kann leicht überprüft werden, ob die
korrekte Anzahl von Argumenten übergeben wurde:
sub max {
my ($x, $y) = @_;
if (@_ != 2) {
print "WARNUNG! &max braucht genau 2 Argumente!\n";
}
if ($x > $y) { return $x; } else { return $y; }
}

Allerdings ist es besser, die Subroutine max so umzuschreiben, dass
sie mit einer beliebigen Anzahl von Argumenten umgehen kann:
sub max {
my ($max_aktuell) = shift @_;
foreach (@_) {
if ($_ > $max_aktuell) { $max_aktuell = $_; }
}
return $max_aktuell;
}
Programmierkurs für absolute Anfänger – Sitzung 11
29
Leere Argumentlisten

Angenommen, die neue Subroutine max wird im
Programm folgendermaßen aufgerufen:
@zahlen = <STDIN>;
chomp @zahlen;
$maximum = &max(@zahlen);

Was passiert, wenn @zahlen die leere Liste enthält,
weil die eingelesene Datei leer ist?



Die Subroutine max wird mit einer leeren Liste als Argument
aufgerufen.
$max_aktuell erhält den Wert undef, und die foreachSchleife wird keinmal ausgeführt.
Damit ist der Rückgabewert undef.
Programmierkurs für absolute Anfänger – Sitzung 11
30
Beispiel: Indexbestimmung
use strict;
my @namen = ("Fred", "Otto", "Betty", "Dino", "Paul");
my $index = &welchen_index_hat("Dino", @namen);
print "index von Dino: $index\n";
sub welchen_index_hat {
my ($element, @liste) = @_;
foreach my $i (0..$#liste) {
if ($element eq $liste[$i]) {
return $i;
}
}
return -1;
}
Programmierkurs für absolute Anfänger – Sitzung 11
31
Beispiel: Subroutine summe

Die Subroutine summe erhält als Argument eine Liste von Zahlen
und gibt die Summe dieser Zahlen zurück.
my @zahlen = 1..1000;
my $summe = &summe(@zahlen);
print "Die Summe der Zahlen von 1 bis 1000 ist
$summe.\n";
sub summe {
my $summe;
foreach (@_) {
$summe += $_;
}
return $summe;
}
Programmierkurs für absolute Anfänger – Sitzung 11
32
Herunterladen