Lesen und Schreiben von Daten
Transcription
Lesen und Schreiben von Daten
4. Lesen und Schreiben von Daten Input vom Terminal und von Files Output in Files und auf Konsole komprimierte Files temporäre Files 4-1 Input und Output in Perl Öffnen von Files mit open HANDLE, string STDIN, STDOUT und STDERR sind schon offen string definiert welches File wie geöffnet wird "file" nur lesen (read only) "<file" auch read only ">file" nur schreiben ">>file" anhängen an File "+<file" lesen und schreiben Beispiel: my $file = "/AUTOEXEC.BAT"; open FH, $file or die "Error opening $file: $!\n"; Weglassen von \n gibt auch Stelle aus, wo Fehler auftrat 4-2 Indirekte Filehandles gängige Praxis: open F, $filename damit ist F in Symboltabelle gespeichert und sichtbar alter mit F verknüpfter offener Stream wird geschlossen Ausweg: indirekte Filehandles (seit perl 5.6) open my $FILE, $filename erzeugt anonymes Handle, $FILE ist Referenz darauf $FILE nicht in Symboltabelle (lexikalische Variable) kann wie normales Filehandle benutzt werden kann an Subroutinen übergeben werden 4-3 open mit 3 Parametern Öffnen von Files auch mit open HANDLE, mode, filename; mode gibt an, wie File zu öffnen ist ( '<', '>', '>>', usw.) Vorteil: keine Mischung von Name und Art des Öffnens erst ab perl 5.6 Beispiel mit indirektem Handle und 3 Parameter open: open my $F, '<', $file or die "Error in open: $!\n"; 4-4 I/O mit externen Programmen "cmd|" liest von cmd "|cmd" schreibt nach cmd Gleichzeitiges Lesen und Schreiben in Pipe nicht möglich, aber: es gibt perl Funktionen open2/open3 (nicht für Windows) Funktionen benutzbar nach use IPC::Open2; werden für Interprozesskommunikation benutzt (IPC) Queries werden an eine Output pipe gesendet (an daemon) Antworten werden von Input pipe gelesen (von daemon) 4-5 Input Operationen Von einem File liest man mit <HANDLE> im skalaren Kontext wird eine Zeile gelesen im List Kontext wird ganzes File in array gelesen!!! Um Handle in Variable zu speichern, kann man auch Globbing Operator * benutzen: $handle = \*HANDLE; $/ (InputRecordSeparator) definert was Zeile ist! undef $/; $/=""; $/ = \num; #ganzes File #ein Absatz (bis zu Leerzeile) #ein Record der Länge <=num sogar Zeichenfolgen sind als Separator erlaubt 4-6 Input Operationen (2) Spezielle Funktion von <> auch Diamantoperator genannt liest aus Files, deren Namen in @ARGV stehen danach bzw. stattdessen wird von STDIN gelesen Spezielles Handle DATA liest Text, der nach __DATA__ oder __END__ im aktuellen Skript steht Einzelne Zeichen liest man mit $c=getc HANDLE; wenn HANDLE weggelassen wird, dann von STDIN Nach Ende des I/O Files schliessen: close HANDLE; 4-7 Beispiel: File input # DATA Stream is already open (lines after __DATA__) { # a new scope starts here local $/; # only valid in this block $/ = ""; my $headers = <DATA>; # read mail headers in one go close DATA; print $headers if $headers; } open PROG, "Lektion2.pl"; my $magic = getc(PROG) . getc(PROG); close PROG; print "Lektion2.pl is a script\n" if $magic eq "#!"; 4-8 Die readline Funktion Term::ReadLine ist für zeilenweise Input zuständig Standard perl liefert Grundfunktionen Erweiterte Funktionen erst mit Zusatzmodulen Kommandozeileneditor, Kommandozeilenhistory, ... Term::ReadLine::Perl oder Term::ReadLine::Gnu sollten unbedingt nachinstalliert werden damit dann Inputstile wie raw, hidden, cooked Ist bei DESY bereits installiert bzw. wurde hier geübt Term::ReadKey hat ähnliche Bedeutung Installieren Sie bitte Term::ReadKey mit cpan 4-9 Programmierung eines Passwortdialogs use Term::ReadKey; my $in = \*STDIN; # reference to a handle! ReadMode 2, $in; #hidden input print "Your Password please: "; my $password = ReadLine 0, $in; print "\nYour Password was $password"; ReadMode 0, $in; #normal input Schreiben Sie diesen Dialog unter Verwendung von Term::ReadLine::Gnu und Anzeige der Zeichen (*) 4-10 Lesen von Directories analog zu Lesen von Files: opendir HANDLE, string; while (<HANDLE>) { readdir HANDLE; #$_ now contains Filename ... } #or without while: @files = readdir HANDLE; closedir HANDLE; Was ist besser: mit oder ohne while ? liefert nur File/Directory Namen ohne Pfade Von readdir werden alle Files und Directories zurückgeliefert (auch . und ..) 4-11 Ausgabeoperationen Output mit print HANDLE list # kein Komma! Bessere Kontrolle mit printf HANDLE format,list Ohne HANDLE Angabe erfolgt Output nach STDOUT Alternative zu print (ungebräuchlich): Benutzung von FORMATen und der Funktion write Bei Verwendung von pipes oder Output in Files kann ein flush der Puffer nach jedem print/write sinnvoll sein (”ungepuffert”): $|=1; 4-12 Beeinflussung von print print kann durch $\, $, und $" beeinflusst werden $\ wird nach jedem print ausgegeben { local $\="\n"; # \n gets added now print "no linefeed required here"; } $, wird zwischen Listenelementen ausgegeben { local $,=","; #elements get separated by , print "System is $^O", "did you know?\n";} $" wird zwischen Elemente in "Strings" eingefügt { local $"="-"; local $\="\n"; local $,="+"; my @a=qw(1 2); print @a,"@a"; }# 1+2+1-2\n 4-13 Low Level I/O Für bessere Kontrolle und Geschwindigkeit, aber schwierigere Syntax sysopen HANDLE, PATH, FLAGS, [MASK] öffnet Files read , sysread liest eine Zahl von Bytes (wie getc) use Fcntl; # provides constants such as O_RDONLY sysopen PROG, "Lektion2.pl", O_RDONLY; sysread PROG, $magic, 2, 0; close PROG; print "Lektion2.pl is a script\n" if $magic eq "#!"; syswrite schreibt eine Zahl von Bytes tell/telldir/seek/seekdir arbeiten wie in C truncate verkürzt ein File 4-14 Lesen von komprimierten Files Compress::Zlib realisiert I/O mit komprimierten Files # determine current directory # for portable file name manipulation see also File::Spec use Cwd; use Compress::Zlib; # read a gzipped file and count the lines in there my $file = shift; my $lines = 0; my $gz = gzopen($file, "rb") or die "Cannot open $file: $gzerrno\n" ; while ($gz->gzreadline($_) > 0) { $lines++; } die "Error reading from $file: $gzerrno" . ($gzerrno+0) . "\n" if $gzerrno != Z_STREAM_END ; $gz->gzclose() ; print "File $file contains $lines lines\n"; 4-15 Schreiben von komprimierten Files Compress a file with maximum compression Use the same module: Compress::Zlib lookup the documentation using perldoc Get more info with man zlib Finally find the real info in /usr/include/zlib.h (UNIX) See file 04gzwrite.pl for a working script 4-16 Arbeiten mit Files Viele Funktionen den UNIX/NT Kommandos nachgebildet chdir(cd), chmod, chown(chown, chgrp) link (ln), symlink (ln -s) mkdir, rmdir, unlink (rm), utime (setzt access und modify time, erzeugt kein File) Resultat ist eine Liste Abfrage von Fileinfos mit stat, lstat, Testoperatoren my $file = "Lektion1.pl"; my ($mode, $size) = (stat $file)[2,7]; printf "File $file (length %d) has mode bits %o\n", $size, $mode; Selektiere Elemente 4-17 Temporäre Files Kann großes Sicherheitsloch bedeuten. Der falsche Code: open (TMP, "/tmp/foo.$$") ...# seen in many places Um gegen Sicherheitsattacken immun zu sein, sollten Tempfiles nicht in world writable directories angelegt werden keine vorhersagbare Namen haben nicht bereits existieren Hacker können einen Hard- oder Symlink dort anlegen, wo gerade ein Tempfile angelegt werden soll. Damit können evtl. wertvolle Daten überschrieben werden. Besonders wichtig, wenn Skript mit root Privilegien läuft 4-18 Temporäre Files (2) Die korrekte Methode ohne File::Temp use POSIX; do { $name=tmpnam(); } until sysopen(TMP,$name,O_RDWR|O_CREAT|O_EXCL,0600); # do something with TMP close TMP; unlink $name; Ab perl 5.6 ist File::Temp im Basispaket enthalten use File::Temp "tempfile"; my ($tmp, $filename) = tempfile(); # do something with $tmp close $tmp; unlink $filename; n Können Tempfiles automatisch gelöscht werden? 4-19 Dokumentation zu I/O allgemeines Tutorial Bidirektionales I/O IO Layers Funktionsdefinitionen perldoc perlopentut perldoc perlipc perldoc perlIO perldoc -f open, sysopen, opendir, readdir, flock, .... KontrollFragen Wie kann ich einzelne Zeichen von der Konsole lesen, ohne auf <ENTER> warten zu müssen? Kann man Puffer noch anders "flushen"? (z.B für STDERR) Tipp: was macht perldoc -q ? 4-20