Thread Datei einlesen (38 answers)
Opened by Fredl at 2012-03-09 15:50

FIFO
 2012-03-12 11:46
#156771 #156771
User since
2005-06-01
469 Artikel
BenutzerIn

user image
Guest Fredl
Hallo perl-community,

Ich bin Anfänger im Perl (überhaupt Anfänger im Programmieren) ...


Hallo Fredl,
schon verschreckt von der Diskussion? Der Code in meinem ersten Posting mag Dir umständlich vorkommen, aber es hat seine Gründe, Programme von vorneherein defensiv zu schreiben.

Als Anfänger freut man sich, wenn überhaupt was funktioniert.

Als Programmier-Halbstarker hat man das Gefühl, die Sache im Griff zu haben und möchte coolen Code schreiben. Kürzer, eleganter und auch ein bisschen so, dass die anderen sehen, dass kein Anfänger am Werk ist.

Mit zunehmender Routine rückt etwas anderes in den Vordergrund: Der Code muss stabil und wartbar sein, insbesondere wenn man ihn in anderen Projekten wiederverwenden will. Ein guter Test ist es, den eigenen Code nach 2-3 Monaten nochmal zu lesen. Wenn man nicht auf Anhieb nachvollzieht, was das Programm da tut, ist es ineffizienter Code, denn es kostet mich jedesmal Zeit, ihn zu verstehen.

Das folgende (elegante?) 4-Zeilen-Programm ersetzt in D:\Versuch\demo.dat alle x (case-insensitive) durch Y:
Code (perl): (dl )
1
2
3
4
open(FILE, 'D:\Versuch\demo.dat');
map { s/x/Y/ig } (@tmp = <FILE>);
open(FILE, '>D:\Versuch\demo.dat');
print FILE for @tmp;

Dabei ist einiges durch die Features von Perl wunderbar vereinfacht, z.B. die implizite Verwendung der Spezialvariable $_, das implizite close() beim erneuten open() desselben Filehandles, das Weglassen des Standardmodus '<' beim ersten open(). Die eigentliche Modifikation der Daten passiert in Zeile 2:
Die ganze Datei wird in das Array @tmp eingelesen, je eine Zeile als Array-Element. Durch die Zuweisung (=) entsteht ein sog. Lvalue, der an die map-Funktion weitergereicht wird, die wiederum durch die Elemente von @tmp iteriert und dabei dem gerade aktuellen Element den Aliasnamen $_ gibt. Mit diesem $_ kann man nun einiges anstellen, alle Änderungen wirken sich sofort auf das Arrayelement aus (hier die Ersetzung: s/x/Y/ig).
Das Abspeichern in Zeile 4 verwendet wieder die "magische" $_-Variable, die bei print() als Default ausgegeben wird.
Ausformuliert stünde da
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
open(FILE, 'D:\Versuch\demo.dat');
@tmp = <FILE>;
map { $_ =~ s/x/Y/ig } @tmp;
close(FILE);
open(FILE, '>D:\Versuch\demo.dat');
for (@tmp) { # oder (identisch) foreach
    print FILE $_;
}
close(FILE);


Warum erzähle ich das? Weil der 4-Zeilen-Code zwar perlig, aber unsicher ist und unbrauchbar, wenn es nicht um diesen kleinen Spezialfall geht.
Was ist, wenn open() scheitert?
Wie baue ich komplexere Dateiänderungen ein?
Was ist, wenn ich mal nicht nur diese eine, sondern z.B. alle .dat-Files ändern will?
Was ist, wenn ich fremden Code mitbenutze (Module, sehr ratsam), und dieser irgendwo etwas mit einem Filehandle names FILE anstellt (und damit meine Datei ruiniert, denn mein Handle FILE ist global)?

Nochmal der Code von oben, habs für eine andere Datei nochmal abgetippt:
Code (perl): (dl )
1
2
3
4
open(FILE, 'D:\Versuch\demo2.dat');
map { s/x/Y/ig } (@tmp = <FILE>);
open(FILE, '>D:\Versuch\demo2.dat');
print FILE for @tnp;


Ich führe ihn aus und Panik!, meine Datei ist leer! Der Grund ist die falsche Schreibweise von @tmp in Zeile 4. Perl erzeugt da einfach ein neues Array @tnp ohne Inhalt; Auf die falsche Schreibweise hätte Perl mich hingewiesen, hätte ich use warnings; (oder besser auch use strict;) an den Anfang des Skriptes gestellt (und damit komplett überflüssige Threads im Forum vermieden :).
Die Datei ist aber deswegen leer, weil der zweite open()-Aufruf im Schreibmodus den Dateizeiger auf den Dateianfang setzt, und das wird durch use warnings nicht verhindert, aber durch use strict, das bereits das Kompilieren abbricht.
Also verwende ich bei Skripten, die Daten verändern, fast immer temporäre Dateien/Backups und gebe den Schritt zum Löschen/Umbenennen erst nach ausreichenden Tests frei.

Vielleicht zeigt Dir das ein wenig, warum hier über TMTOWTDI debattiert wird ...

Gruß FIFO

Editiert von FIFO: typo

Editiert von FIFO: # vor warnings/strict entfernt :)
Last edited: 2012-03-12 18:42:43 +0100 (CET)
Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it? -- Brian Kernighan: "The Elements of Programming Style"

View full thread Datei einlesen