Seite 1 von 1

Dateioperationen -- Anzahl der Zeilen

Verfasst: Montag 23. Dezember 2002, 14:07
von Milan
ich hab mal wieder ein Problem. Ich hab eine sehr lange Datei, von der ich nicht weiß, wieviele Zeile sie hat. Da ich das aber brauche hab ich mir mal folgenden Algorithmus gebastelt:

Code: Alles auswählen

f=open(filename,'r')
lines=0L
for line in f.xreadlines():
    lines+=1L
f.close()
Die Frage ist nun, ob es nicht eine schnellere Variante gibt. mit tell und seek kann man ja die Zeilenposition bestimmen, aber leider nur byteweise. Gib es nich auch eine Methode dafür? Oder ist das wirklich die schnellste Variante, die es dafür gibt?

Verfasst: Montag 23. Dezember 2002, 15:24
von ASCII158
mal eine dumme nebenfrage: was soll das "L" hinter den Zahlen?

Verfasst: Montag 23. Dezember 2002, 15:56
von RicmanX
Das L steht für LongInteger, d.h. für Zahlen die verdammt groß sind und sonst nicht in den Speicher passen würden.

Verfasst: Montag 23. Dezember 2002, 16:50
von hans
Auf die Gefahr hin dass ich mich unbeliebt mache: Unter Linux / Unix würde ich einen Rückgriff auf das Systemkommando wc machen.

Code: Alles auswählen

wc -l Dateiname # gibt Anzahl der Zeilen
wc -l Dateiname* # gibt Dateinamen und Anzahl der Zeilen
Schneller bekomme ich das mit keiner anderen Routine hin.

Ich weiß nicht ob es bei Windows eine API - Funktion dafür gibt. Und MAC?

Hans

Verfasst: Montag 23. Dezember 2002, 19:06
von Milan
ich möcht nicht unbedingt Treaths oder externe Programme nutzen, da das unabhängig sein soll und sich was äußeres ja immer ändern kann. aber auch wenn, wüsste ich weder für win noch für mac ein passendes Programm. das ist ja mein Problem... :?

Verfasst: Montag 23. Dezember 2002, 20:42
von Beyond
Ich denke die xreadlines-Variante ist schon aüßerst schnell, da xreadlines in C programmiert ist. In Python selbst bekommst Du vmtl. nichts schnelleres und es bleibt auch nichts überig außer die Datei Byte für Byte zu lesen. Man weiß ja nicht wo Zeilenumbrüche sind. Schneller wäre es wenn Du die Länge der einzelnen Zeilen kennst oder Dich mit einer Schätzung zufrieden gibst.

Verfasst: Montag 23. Dezember 2002, 21:09
von Milan
nö... muss es genau wissen. aber wenns nichts schnelleres gibt kann ich damit leben. thx.

Verfasst: Montag 23. Dezember 2002, 22:31
von hans
Probieren geht über studieren. Mein Wald und Wiesen PC bringts bei ca. 2,5 Millionen Datensätzen (ca. 175 MB) immerhin auf 30 Sekunden. Ein vernünftiger Server sollte das eigentlich unter 10 Sekunden schaffen.

wc -l scheint auch nicht wesentlich schneller zu arbeiten.

Hans

Verfasst: Montag 23. Dezember 2002, 22:35
von Beyond
Klar, weil xreadlines in C programmiert ist und das ganze Python-Programm ja nicht sehr viel mehr macht. Schließlich muß die gesammte Datei gelesen werden, da bremst die Festplatte wohl.

Erstaunlich schnell ist tar. Den Quellcode wollte ich mir mal ansehen.

cu beyond

Verfasst: Montag 23. Dezember 2002, 23:00
von hans
habe zwar keine c Kenntnisse, aber vermutlich liest tar einen kompletten Block (Sektor?) von der Platte und hängt ihn so an die Datei an ohne diesen zu analysieren. Wenn du Texte liest, kannst du das doch nur Zeichen für Zeichen machen bis ein Zeilenende kommt. funktionen die ein ganze Zeile lesen sind m. E. doch nur abgeleitet um zu vereinfachen.

Hans

Verfasst: Dienstag 24. Dezember 2002, 02:39
von Dookie
Hallo,

das Geheimnis ist ein buffer, hier mal das Prinzip:

Code: Alles auswählen

reserviere 100000 Bytes für den buffer
setze Zeilenzähler auf 0
öffne Datei
solange noch nicht EOF erreicht ist:
    lese 100000 Bytes aus Datei in den buffer
    zähle alle Zeilenumbrüche im buffer
    erhöhe Zeilenzähler um die gezählten Zeilen
schließe Datei
das macht wc so schnell, egal obs in C oder Pascal oder sonstwas programmiert wäre. Natürlich müsste mann bei einem richtigen Programm noch abfragen, ob auch 100000 Bytes gelesen wurden um nicht über das Ende hinaus Zeilenumbrüche zu lesen.


Gruß

Dookie

Verfasst: Dienstag 24. Dezember 2002, 03:06
von Beyond
wc ist ja eben nicht besonders schnell. Aber tar. Ein Buffer gehört dazu, das geht mit Python aber auch problemlos

Code: Alles auswählen

bla= file.read(bufSize)
Das für Python in C implementierte xreadlines wird das auch so machen. Schließlich muß aber noch den Buffer nach "newlines" durchsehen.

Für ein tar-Kopieren ist dies nicht erforderlich. Ich habe mir überlegt ob es bei besseren OS Linux/Unix/BSD etc. einen Befehl gibt "Kopiere Daten von Device A nach Device B". Macht hinsichtlich eines möglichen SCSI-Controllers äußerst viel Sinn und würde auch die Geschwindigkeit von tar erkären. Denn entweder das Betriebssystem erledigt das Kopieren der Daten oder sogar ein eigener Prozessor/Controller.

cu beyond

Verfasst: Dienstag 24. Dezember 2002, 13:55
von hans
Beyond hat geschrieben:Ich habe mir überlegt ob es bei besseren OS Linux/Unix/BSD etc. einen Befehl gibt "Kopiere Daten von Device A nach Device B".
:?::?::?: Du gibst zu, mit einem "minderwertigem" OS zu arbeiten :?::?::?: :D
Bitte keinen Flame starten :!:

Also Linux / UNIX kennt eigentlich nicht viel von Hardware. Man spricht alles nur als Datei an. Ein Beispiel mit tar

Code: Alles auswählen

# sichert mein Homverzeichnis nach /tmp/hans.tar
tar cvf /tmp/hans.tar  /home/hans
# sichert mein Homeverzeichnis auf DAT
tar cvf /dev/rct0 /home/hans 
die Gerätedatei (/dev/rct0) kann allerdings von System zu System unterschiedlich benannt sein.

Hans

Verfasst: Dienstag 24. Dezember 2002, 14:30
von Beyond
Nein.

"Mit Linux wär das auch passiet"

"Internet Explorer ist der Standard und das ist gut so"

:D :D :D :D Einige beliebte Sprüche aus den Heise-Forum :D :D :D :D

Ich verwende hauptsächlich Linux, aber ich habe mich bisher nicht mit Kernel-Programmierung auseinander gesetzt, daher weiß ich nicht ob es entsprechende Befehle gibt.

Alle OS (sogar Windows) können etwas mit Busmaster-Karten etc. anfangen. Dann geht das lesen/schreiben halbwegs schnell, weil die Sachen von alleine im Arbeitspeicher landen/von dort gelesen werden. Richtig schnell wäre aber, die Daten nicht erst in den Arbeitsspeicher zu laden und dann wieder von dort wegzukopieren, sondern eben direkt von Gerät A nach Gerät B. Eine solche Unterstützung müßte dann in den entsprechenden Treibern (Kernel oder Module) implementiert sein.

Als Benutzer kriegt man von alle dem natürlich nichts mit. Man sagt einfach zu Device xy kopieren. Wie das intern geschieht, weiß man nicht und muß es auch nicht wissen. Das ist wie bei einem RAID. Da sieht man normalerweise auch nur eine "Platte". Man kann aber auch den RAID als physische Devices betrachten, wenn man weiß wie die entsprechenden Devices heißen. Das ist aber meist nicht Zeil der Sache (außer man will einen größeren Datenschaden reparieren :cry:)

Frohe Weihnachten,
beyond

Verfasst: Dienstag 24. Dezember 2002, 15:03
von hans
Sorry wolte die nicht zu nahe treten, aber besseres Betriebsystem wie hattest du geschrieben. Ich fand das soooo einladend. :D

Ich habe aber jetzt verstanden was du meinst. Da muß ich leider passen. Da gehts doch ziemlich ans eingemachte. Mußt du vielleicht mal bei www.linuxforen.de oder anderswo nachharken.

Man könnte ja auch eine RAM Disk in betracht ziehen, aber dann muß ich die Datei mindestens einmal kopieren. Würde sich auch nur lohnen, wenn die Datei mehrfach durchsucht werden muß.

Verfasst: Dienstag 24. Dezember 2002, 16:11
von Dookie
Hallo nochmal,

also ums Ram wirst nicht herum kommen, nichtmal Raid-Controller können von einer Festplatte auf die andere direkt kopieren. Abgesehen davon bremst bei DMA-Platten das ram nicht, da dessen zugriffszeit doch um einiges höher liegt als bei Festplatten. Was eben aufhält, ist das Lesen/Schreiben auf Platte, nicht das Kopieren im Ram. Darum bringt hier auch C/C++ nix. Ausserdem was ist bei unterschiedlichen Festplattengeometrien, eine hat eine Blockgröße von 1024 Byte, eine andere vielleicht 2048, wohlgemerkt lowlevelmässig. Da würde so ein Direktkopieren schnell mal Müll verursachen.


Gruß

Dookie