EMZETT.
Login

Kurz: Moderne Perl-Skripte nutzen die Dreiargument-Form von open mit lexikalischem Dateihandle und prüfen immer auf Fehler:

Teil des Kurses Perl

Kapitel 7 von 11 im Kurs Perl (Abschnitt „Praxis“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Dateien lesen und schreiben

Moderne Perl-Skripte nutzen die Dreiargument-Form von open mit lexikalischem Dateihandle und prüfen immer auf Fehler:

use strict; use warnings;
use File::Temp qw(tempdir);
my $dir = tempdir(CLEANUP => 1);
my $pfad = "$dir/demo.txt";
 
open(my $out, '>', $pfad) or die "Kann $pfad nicht schreiben: $!";
print $out "Zeile 1\n";
printf $out "%s hat %d Punkte\n", "Mia", 120;
print {$out} "Zeile 3\n";
close($out);
 
open(my $anh, '>>', $pfad) or die $!;       # anhängen
print $anh "Zeile 4\n";
close $anh;
 
open(my $in, '<', $pfad) or die "Kann nicht lesen: $!";
while (my $zeile = <$in>) {
    chomp $zeile;
    print "$.: $zeile\n";                    # $. = Zeilennummer
}
close $in;
 
open($in, '<', $pfad) or die;
my @alle = <$in>;                            # alle Zeilen auf einmal
close $in;
print "Zeilen: ", scalar(@alle), "\n";
 
open($in, '<', $pfad) or die;
my $inhalt = do { local $/; <$in> };         # komplette Datei als ein String
close $in;
print "Länge: ", length($inhalt), "\n";
 
if (open(my $fehler, '<', "$dir/gibt-es-nicht")) { close $fehler }
else { print "Fehler: ", $! =~ s/ at.*//r, "\n"; }

Ausgabe:

1: Zeile 1
2: Mia hat 120 Punkte
3: Zeile 3
4: Zeile 4
Zeilen: 4
Länge: 43
Fehler: No such file or directory
ModusBedeutung
<lesen
>schreiben (überschreibt)
>>anhängen
+<lesen und schreiben

Für Text mit Umlauten: open(my $fh, '<:encoding(UTF-8)', $pfad).

Dateitests und Verzeichnisse

use strict; use warnings;
use File::Temp qw(tempdir);
use File::Spec;
use File::Basename qw(basename dirname fileparse);
my $dir = tempdir(CLEANUP => 1);
mkdir "$dir/unter" or die;
for my $n (qw(a.txt b.txt c.log)) {
    open(my $f, '>', "$dir/$n") or die; print $f "x" x 10; close $f;
}
print "Datei\n" if -f "$dir/a.txt";
print "Ordner\n" if -d "$dir/unter";
print "Größe: ", -s "$dir/a.txt", "\n";
print "nicht vorhanden\n" unless -e "$dir/nix";
print "lesbar\n" if -r "$dir/a.txt";
 
my @txt = sort map { basename($_) } glob("$dir/*.txt");
print "@txt\n";
opendir(my $dh, $dir) or die;
my @eintraege = sort grep { !/^\./ } readdir($dh);
closedir $dh;
print "@eintraege\n";
 
print basename("/a/b/c.txt"), " ", dirname("/a/b/c.txt"), "\n";
my ($name, $pfad, $endung) = fileparse("/a/b/bericht.txt", qr/\.[^.]*/);
print "$name | $endung\n";
print File::Spec->catfile("a", "b", "c.txt"), "\n";
rename "$dir/a.txt", "$dir/z.txt" or die;
unlink "$dir/z.txt";
print "gelöscht\n" unless -e "$dir/z.txt";

Ausgabe:

Datei
Ordner
Größe: 10
nicht vorhanden
lesbar
a.txt b.txt
a.txt b.txt c.log unter
c.txt /a/b
bericht | .txt
a/b/c.txt
gelöscht

Kommandozeile, Umgebung, Programme

use strict; use warnings;
@ARGV = ("datei.txt", "--verbose");           # normalerweise vom Aufruf gefüllt
print "Argumente: @ARGV (", scalar(@ARGV), ")\n";
my $datei = shift @ARGV;
print "Erstes: $datei\n";
print "PATH vorhanden\n" if exists $ENV{PATH};
print "Skript: $0\n" if 0;
 
my $ausgabe = `echo Hallo vom Betriebssystem`;      # Backticks: Ausgabe einfangen
print $ausgabe;
my $status = system("true");                        # system: Status (0 = Erfolg)
print "Status: $status\n";
my @zeilen = `printf 'a\\nb\\n'`;
print scalar(@zeilen), " Zeilen\n";
 
use Getopt::Long;
@ARGV = ("--name=Mia", "--anzahl", "3", "--verbose", "rest");
GetOptions("name=s" => \my $name, "anzahl=i" => \my $anzahl, "verbose" => \my $verbose) or die;
print "name=$name anzahl=$anzahl verbose=$verbose rest=@ARGV\n";

Ausgabe:

Argumente: datei.txt --verbose (2)
Erstes: datei.txt
PATH vorhanden
Hallo vom Betriebssystem
Status: 0
2 Zeilen
name=Mia anzahl=3 verbose=1 rest=rest

Daten aufbereiten: sprintf, sort, Reports

use strict; use warnings;
my @daten = (["Mia", 17, 1.68], ["Tom", 25, 1.82], ["Zoe", 31, 1.7]);
printf "%-6s %5s %7s\n", "Name", "Alter", "Größe";
print "-" x 20, "\n";
printf "%-6s %5d %7.2f\n", @$_ for sort { $b->[1] <=> $a->[1] } @daten;
 
my $csv = "name,punkte\nMia,120\nTom,80\n";
open(my $fh, '<', \$csv) or die;
my $kopf = <$fh>; chomp $kopf;
my @spalten = split /,/, $kopf;
my @zeilen;
while (<$fh>) {
    chomp;
    my %z; @z{@spalten} = split /,/;
    push @zeilen, \%z;
}
print join(", ", map { "$_->{name}=$_->{punkte}" } @zeilen), "\n";

Ausgabe:

Name   Alter Größe
--------------------
Zoe       31    1.70
Tom       25    1.82
Mia       17    1.68
Mia=120, Tom=80

Merke

  • open(my $fh, '<', $pfad) or die "...: $!", Modi < > >>
  • Zeilenweise lesen mit while (<$fh>) und chomp
  • Dateitests: -e -f -d -s -r -w; glob, opendir, File::Spec, File::Basename, File::Temp
  • @ARGV, %ENV, Backticks und system; Getopt::Long für Optionen
  • UTF-8: '<:encoding(UTF-8)'

Übungsaufgabe

Lies eine Textdatei ein, zähle die Wörter und schreibe die zehn häufigsten in eine neue Datei.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Reguläre Ausdrücke

Weiter: Referenzen und komplexe Datenstrukturen

Alle Kapitel: Perl im Überblick