Forum: PC-Programmierung Python buffern bei Datei lesen


von Wutang (Gast)


Lesenswert?

Hi,

ich versuche die Frage gank knapp zu stellen:

Wenn ich in Python ein (text)file öffne, kann ich da Zeilenweise drüber 
iterieren. Also per
1
for line in file:
2
    print(line)

ich kann auch einen größeren Block lesen:
1
buffer = file.read(512)
2
for foo in buffer:
3
    print(foo)
Wenn ich jetzt aber in dem Buffer iteriere ist das Zeichenweise.

Wie kann ich größere Sektoren per file.read() holen und da dann auch 
Zeilenweise iterieren? (Oder passiert das ggf. sogar 'unter der Haube')?


danke euch!

von Thomas Barends (Gast)


Lesenswert?

Ist das hier was?

myfile=open('myfilename.txt','r')
mylines=myfile.readlines()
myfile.close()

for line in mylines:
    # DO THING WITH LINE

von Sheeva P. (sheevaplug)


Lesenswert?

Thomas Barends schrieb:
> Ist das hier was?
>
> myfile=open('myfilename.txt','r')
> mylines=myfile.readlines()
> myfile.close()
>
> for line in mylines:
>     # DO THING WITH LINE

Das ist zwar richtig, aber je nach Anwendungsfall leider nur so... 
"halbschön", da die Datei auf diese Weise komplett in den Speicher 
geladen wird, was bei sehr großen Dateien etwas... problematisch werden 
kann. Zudem entfernt die Methode "readlines()" leider nicht den 
Zeilenumbruch am Ende der Zeilen.

Allerdings kann unser TO auf seinen Puffer die Methode "splitlines()" 
anwenden, die die Zeilenumbrüche entfernt, sich aber nicht an 
Zeilenumbrüchen orientiert. Ein "read(512).splitlines()" enthält im 
letzten Feld also mit einer sehr hohen Wahrscheinlichkeit eine 
unvollständige Zeile. Deswegen wäre so etwas wie
1
with open(filename, 'r') as ifh:
2
    bufferlist = ifh.read(BUFSIZE).splitlines()
3
    bufferlist[-1] += ifh.readline().strip()

vielleicht ein hübscherer Weg, die letzte Zeile vollständig zu lesen 
(readline()) und auch dort den Zeilenumbruch zu entfernen (strip()).

von Imonbln (Gast)


Lesenswert?

Sheeva P. schrieb:
> vielleicht ein hübscherer Weg, die letzte Zeile vollständig zu lesen
> (readline()) und auch dort den Zeilenumbruch zu entfernen (strip()).

Vielleicht kann man das so umsetzen, das Ganze ist ein Generator, 
welcher die Datei Sektoren weise einließt und zeilenweise ausgibt.
1
from typing import Iterator
2
3
def lineread(fname: str) -> Iterator[bytes]:
4
    carry = bytes()
5
    with open(fname, 'rb') as fin:
6
         for chunk in iter(fin.read, b''):
7
             carry += chunk
8
             arr = carry.splitlines()
9
             yield from arr[:-1]
10
             carry = arr[-1]
11
         yield carry

von Imonbln (Gast)


Lesenswert?

Nun auch in Funktioniernd, wenn das universal newline sich auf zwei 
Chunks verteilt.
1
def lineread(fname: str) -> Iterator[bytes]:
2
    carry = bytes()
3
    def rm_univeral_newline(x: bytes) -> bytes: return x.splitlines()[0]
4
    with open(fname, 'rb') as fin:
5
         for chk in iter(fin.read, b''):
6
               carry += chk
7
               arr = carry.splitlines(keepends=True)
8
               for x in arr[:-1]:
9
                   yield rm_univeral_newline(x)
10
               carry = arr[-1]
11
         yield rm_univeral_newline(carry)

von Rolf M. (rmagnus)


Lesenswert?

Wutang schrieb:
> Wie kann ich größere Sektoren per file.read() holen und da dann auch
> Zeilenweise iterieren? (Oder passiert das ggf. sogar 'unter der Haube')?

Ja, das passiert 'unter der Haube' bereits. Der dritte Parameter von 
open() dient dazu, das Buffering zu konfigurieren.

von Vorname N. (mcu32)


Lesenswert?

Einfach mal die Übergabeparameter der Funktion anschauen. Bei PyCharm 
geht das durch simples Anklicken der Funktion.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.