Ein Problem beim Einlesen von Dateien kennen viele: Entweder man liest die Datei komplett in den Arbeitsspeicher ein und "verschleudert" so wertvolle Systemressourcen, oder man liest Zeilen nacheinander ein und hat dann das Problem, daß die jeweils nachfolgende zeile nicht da ist, wenn man sie braucht.
Ein Beispiel für das komplette Einlesen von Dateien
#Datei komplett einlesen
use strict; open (my $IN,'<'.'1.txt'); my @array=(<$IN>); close $IN;
Ein Beispiel für das zeilenweise Einlesen von Dateien
Was passiert hier?
Also, die Datei 1.txt wird wie gehabt geöffnet, das Array vorbereitet, und natürlich ein Counter, der immer von 0 bis 3 läuft. Dieser Counter bestimmt gleich, wann vier Werte eingelesen wurden.
Weiter im Script: In der while-Schleife wird per direkter zuweisung der Eintrag @array[$cou] auf $_ gesetzt. $_ ist die aktuelle Zeile aus der Textdatei.
Danach erhöhen wir den Counter um eins, und wenn er kleiner 4 ist (0 - 3 sind ja vier Werte) wird die nächste Zeile eingelesen.
Sollte der Counter = 4 sein, setzen wir ihn zurück auf 0 für den nächsten Durchlauf und haben die letzten 4 Werte im Array.
Auf diese Weise kann man zum Beispiel Datendateien mit Datensätzen auslesen, ohne sie vollständig einlesen zu müssen.
Zusatz
Aufgrund des kommentars von René Bäcker unten, der natürlich richtig ist, hier noch eine erweiterte Version, die zum Schluß noch die übrig gebliebenen Einträge ausgibt.
while (<$IN>){
@array[$cou]=$_;
$cou++; next if $cou <4;
# die vier Einträge verarbeiten
$cou=0; printjoin("\n",@array); print "\n\n";
@array=();
} # while-Scheife
print "Übrig gebliebene Einträge:\n ".join ("\n",@array) if $cou != 0;
Das Vorgehen ist wie bei dem Script vorher, wenn jedoch am Ende der Counter != 0 ist (also noch Zeilen eingelesen wurden, aber nicht die 4 erreicht haben), werden so die Übrigen ausgegeben.
Weiterer Zusatz
Aufgrund des Vorschlages von Struppi, unten in den Kommentaren, will ich natürlich auch seine Methode nochmal extra aufführen und erläutern.
Die Funktion ist natürlich die Gleiche, es werden immer 4 Zeilen eingelesen und danach ausgegeben. Natürlich würde man "im echten Leben" damit etwas sinvolles anstellen.
Wie funktioniert es?
Also, Datei wird geöffnet und in einer while-Schleife durchlaufen. So wie in meinem Beispiel auch.
Danach wird per Modulo 4 (%4) getestet, ob die aktuelle Zeilenzahl der einzulesenden Datei durch 4 teilbar ist, ohne Rest. $. gibt ja immer die aktuelle Zeilennummer der einzulesenden Datei an (siehe Vordefinierte Variablen). Falls die aktuelle Zeilennummer durch 4 teilbar ist, wird das Ergebnis ausgegeben, ansonsten der nächste Wert geholt.
Nun, funktionieren tuts auch, und das sogar ohne extra Zähler, wie in meinem Beispiel. Ob es performanter ist als mein Beispiel, kann ich jetzt nicht sagen, aber vermutlich ist Struppis Version einen Hauch schneller.
Wie man sieht, gibts eben in Perl immer mehrere Wege, ein Problem umzusetzen.
Danke nochmal für die aufmerksame Mitleserschaft!
Kommentare zum Beitrag "Bestimmte Anzahl von Zeilen aus Datei einlesen"
Kommentar von Renee Bäcker
Was machst Du, wenn die Datei eine Zeilenanzahl hat, die nicht durch 4 teilbar ist? Sollen dann die Zeilen nicht ausgegeben werden?
Meinetwegen die Datei hat 9 Zeilen. Wenn die 9. Zeile auch angezeigt werden soll, dann musst Du das nach der Schleife abfangen. Und Du solltest das Array besser auch leeren als einfach nur den Zähler auf 0 zu setzen. Sonst bekommst Du Probleme wenn Du die überzähligen Zeilen (z.B. die oben genannte 9. Zeile) auch ausgeben willst da dann noch alte Zeilen im Array stehen.
Kommentar von Admin
Das stimmt natürlich, wenn die Anzahl der Zeilen nicht durch 4 teilbar ist. Allerdings meinte ich ja eben Datensätze, die dann eben immer eine Zeilenanzahl von 4 haben.
Eine "runderneuerte" Version gibts jetzt aber trotzdem als Zusatz oben.
Kommentar von Struppi
Erstmal finde ich einen Perlblog sehr gut und so wie es aussieht lernst du damit, was für viele bestimmt hilfreich ist die auch mit Perl anfangen (der FlipFlop war für mich auch neu).
Auch ich bin - nach 8 Jahren Perl - immer noch auf der Suche von und finde auch Perlgeheimnissen (http://perldesignpatterns.com/?HomePage ist z.b. auch eine sehr gute Seite um richtig tief einzusteigen).
Aber mal ein paar Tricks, von denen ja Perl viele bietet, das Beispiel läßt sich z.b. auch mit der vordefinierten Variabel $. umsetzen, in Verbindung mit dem module Operator, das Skript könnte dann in etwa so aussehen:
#! /usr/bin/perl -w use strict;
my $tmp = ''; while (<DATA>) { $tmp .= $_; next if $. % 4; print "$tmp", ( '-' x 50 ), "\n"; $tmp = ''; } # while-Scheife
print "Übrig gebliebene Einträge:\n$tmp" if $tmp;
und da ist gleich noch ein Trick, alles was am Ende einer Perl Datei nach __DATA__ steht kann mit <DATA> wie eine Datei eingelesen werden, das erspart dir jedesmal eine separate Datei zu erstellen und du musst nichts öffnen (wobei das für Verwirrung sorgen kann, naja ich find's praktisch, da hat man immer lauffähige Beispiele). Und immer schön use strict und -w oder use warnings benutzen, dadurch fällt es leichter sauberen Code zu schreiben und Fehler zu finden.
Wie auch immer, weiter so!
Kommentar von Admin
Danke für den Vorschlag, ich hab das gleich als Zusatz in den Artikel oben eingefügt.
Kommentar von retnug
Hallo,
unter Unix tut's auch ein
open ($in,"more meineDatei |head -3|")
dann liest er nur die ersten 3 Zeilen ein