Python buffern bei Datei lesen

Gast #6688571
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!
#6711436
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()).
Gast #6711629
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
Gast #6711739
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)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren