/blog/perl


substr() in Perl
[128755 mal gelesen]
foreach in Perl
[117342 mal gelesen]
Arrays in Perl - Besonderheiten
[110577 mal gelesen]
open() - Dateien öffnen in Perl
[98594 mal gelesen]
split() in Perl - Zeichenketten teilen
[90837 mal gelesen]
chomp() in Perl
[85331 mal gelesen]
grep - Listen durchsuchen in Perl
[82604 mal gelesen]
push in Perl
[79790 mal gelesen]
sleep in Perl - Das aktuelle Script warten lassen
[62345 mal gelesen]
print in Perl
[50324 mal gelesen]


Arrays
Dateien
HTPC
Hashes
Leistungsoptimiert
PHP
Perl
RegEx
Schleifen
Script
Skalare
Sonstiges
System
Webserver
Zur Startseite


Freitag, 1.6.2007, 11:55:37 Uhr

Bestimmte Anzahl von Zeilen aus Datei einlesen


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

use strict;
open (my $IN,'<'.'1.txt');
my @array=();

while (<$IN>){
print "$_\n";

}
close $IN;



Wie stellt man es also an, wenn man zeilenweise, zum Beispiel immer vier Zeilen, einlesen möchte?
"Normalerweise" würde man es so machen

use strict;
open (my $IN,'<'.'1.txt');
my @array=(<$IN>);
close $IN;

for (my $i=0;$i<@array;$i+=4){
print join("\n",@array[$i..$i+3]);
print "\n\n";

}


Blöd eben, daß die komplette Datei einglesen werden muß. Bei einer Megabyte großen Datei kanns schon mal Probleme geben...


Ich hab mir da mal sowas einfallen lassen:

use strict;
open (my $IN,'<'.'1.txt');
my @array=();
my $cou=0;

while (<$IN>){
@array[$cou]=$_;
$cou++;
next if $cou <4;

# die vier Einträge verarbeiten
$cou=0;
print join("\n",@array);
print "\n\n";

} # while-Scheife


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.

use strict;
open (my $IN,'<'.'1.txt');
my @array=();
my $cou=0;

while (<$IN>){
@array[$cou]=$_;
$cou++;
next if $cou <4;

# die vier Einträge verarbeiten
$cou=0;
print join("\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.

Sein Code nochmal:

#! /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;


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

Kommentar von Fabian
Hallo zusammen,
ich suche schon etwas im Internet und bin bisher nicht fündig geworden.

Ist es auch möglich bestimmte Zeilen einer Textdatei auszulesen, z.B. nur Zeile 100?



Thema: Perl Dateien

Der Beitrag "Bestimmte Anzahl von Zeilen aus Datei einlesen" wurde 14652 mal gelesen.

Es wurde 2 x über diesen Beitrag abgestimmt.
Die durchschnittliche Beurteilung liegt bei
1 (1 = sehr gut - 6 = grottenschlecht).

Kommentar schreiben  Druckansicht  Seitenanfang 
Beurteilen 






 Zufällige Beiträge im /blog/perl

Arrays in Perl - Besonderheiten

crypt() in Perl - Zeichenketten verschlüsseln

Eine Datei komplett einlesen mit Perl

Was man mit RegEx tun sollte und was nicht - Reguläre Ausdrücke

Die Schwartzsche Transformation - Arrays sortieren nach mehreren Kriterien

Groß-Kleinschreibung in Regular Expression ändern

head einer Webseite einlesen mit Statuscode

join() - Array in Skalar umwandeln - Wie mache ich aus einer Liste eine Zeichenkette?



0.0850081443786621 sec. to build



...Blogsoftware in pure Perl - Powered by a lot of Coffee...


SSD-Festplatte - Wassn das???
Die Transliteration - Nur ein Zeichen in einem Skalar ersetzen
Select - Case in Perl
Windows 7 XP Mode – Wo finde ich den XP-Modus unter Windows 7?
Mac-Adresse beim Apple Macintosh herausfinden
SGN-Funktion für Perl
truncate - Dateigröße verändern in Perl
Eigene IP herausfinden mit Perl
Epoche live in Datum umwandeln
Firefox 3 - Exe-Files downloaden


Von: Fabian
Kommentar:
Hallo zusammen,
ich suche schon etwas im Internet und bin bisher nicht fündig geworden.
Zum Beitrag


Von: Schorschel eastcoast
Kommentar:
Danke. Das hat mir weitergeholfen.
Zum Beitrag


Von: Jessica
Kommentar:
Kann man auch zwei Datein parallel einlesen?

Zum Beitrag


Von: Xtravaganz
Kommentar:
Für

Zum Beitrag


Von: Xtravaganz
Kommentar:
Für

Zum Beitrag



Gesamtverzeichnis
Februar 2010
Dezember 2009
Oktober 2009
Januar 2009
Dezember 2008
November 2008
September 2008
August 2008
Juli 2008
Juni 2008
Mai 2008
April 2008
Januar 2008
Dezember 2007
November 2007
Oktober 2007
September 2007
August 2007
Juni 2007
Mai 2007
April 2007
März 2007
Februar 2007
Januar 2007
Dezember 2006


Mister Wong

RSS-Feed

Heute ist der
13.11.2018

Es ist
17:30:28 Uhr

Ihre IP:
54.90.185.120

Blog-Einträge: 186

Die letzten 24 Stunden im Überblick


Gelesene Beiträge insgesamt:
3740132


Webseiten vergleichen
Kalender mit Feiertagen - 2028
Links finden und testen
Menschliche Datumsangaben
IP zu Domain herausfinden
Time live in Datum umwandeln
Perl für Windows



Mo Di Mi Do Fr Sa So
1234
567891011
12131415161718
19202122232425
2627282930

Impressum