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