Es gibt bereits viele gute Antworten, aber wenn sich Ihre gesamte Datei in einer einzelnen Zeile befindet und Sie dennoch "Zeilen" verarbeiten möchten (im Gegensatz zu Blöcken mit fester Größe), helfen Ihnen diese Antworten nicht weiter.
In 99% der Fälle ist es möglich, Dateien zeilenweise zu verarbeiten. Dann können Sie, wie in dieser Antwort vorgeschlagen , das Dateiobjekt selbst als Lazy Generator verwenden:
with open('big.csv') as f:
for line in f:
process(line)
Allerdings bin ich einmal auf eine sehr sehr große (fast) einzeilige Datei gestoßen, in der das Zeilentrennzeichen eigentlich nicht '\n'
aber war '|'
.
- Zeile für Zeile zu lesen war keine Option, aber ich musste es trotzdem Zeile für Zeile verarbeiten.
- Eine Konvertierung
'|'
in '\n'
vor der Verarbeitung kam ebenfalls nicht in Frage, da einige der Felder dieser CSV enthalten waren '\n'
( Freitext- Benutzereingabe).
- Die Verwendung der CSV-Bibliothek wurde ebenfalls ausgeschlossen, da es zumindest in früheren Versionen der Bibliothek schwierig ist, die Eingabe zeilenweise zu lesen .
Für diese Art von Situationen habe ich das folgende Snippet erstellt:
def rows(f, chunksize=1024, sep='|'):
"""
Read a file where the row separator is '|' lazily.
Usage:
>>> with open('big.csv') as f:
>>> for r in rows(f):
>>> process(row)
"""
curr_row = ''
while True:
chunk = f.read(chunksize)
if chunk == '': # End of file
yield curr_row
break
while True:
i = chunk.find(sep)
if i == -1:
break
yield curr_row + chunk[:i]
curr_row = ''
chunk = chunk[i+1:]
curr_row += chunk
Ich konnte es erfolgreich einsetzen, um mein Problem zu lösen. Es wurde ausgiebig mit verschiedenen Blockgrößen getestet.
Testsuite für diejenigen, die sich selbst überzeugen wollen.
test_file = 'test_file'
def cleanup(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
os.unlink(test_file)
return wrapper
@cleanup
def test_empty(chunksize=1024):
with open(test_file, 'w') as f:
f.write('')
with open(test_file) as f:
assert len(list(rows(f, chunksize=chunksize))) == 1
@cleanup
def test_1_char_2_rows(chunksize=1024):
with open(test_file, 'w') as f:
f.write('|')
with open(test_file) as f:
assert len(list(rows(f, chunksize=chunksize))) == 2
@cleanup
def test_1_char(chunksize=1024):
with open(test_file, 'w') as f:
f.write('a')
with open(test_file) as f:
assert len(list(rows(f, chunksize=chunksize))) == 1
@cleanup
def test_1025_chars_1_row(chunksize=1024):
with open(test_file, 'w') as f:
for i in range(1025):
f.write('a')
with open(test_file) as f:
assert len(list(rows(f, chunksize=chunksize))) == 1
@cleanup
def test_1024_chars_2_rows(chunksize=1024):
with open(test_file, 'w') as f:
for i in range(1023):
f.write('a')
f.write('|')
with open(test_file) as f:
assert len(list(rows(f, chunksize=chunksize))) == 2
@cleanup
def test_1025_chars_1026_rows(chunksize=1024):
with open(test_file, 'w') as f:
for i in range(1025):
f.write('|')
with open(test_file) as f:
assert len(list(rows(f, chunksize=chunksize))) == 1026
@cleanup
def test_2048_chars_2_rows(chunksize=1024):
with open(test_file, 'w') as f:
for i in range(1022):
f.write('a')
f.write('|')
f.write('a')
# -- end of 1st chunk --
for i in range(1024):
f.write('a')
# -- end of 2nd chunk
with open(test_file) as f:
assert len(list(rows(f, chunksize=chunksize))) == 2
@cleanup
def test_2049_chars_2_rows(chunksize=1024):
with open(test_file, 'w') as f:
for i in range(1022):
f.write('a')
f.write('|')
f.write('a')
# -- end of 1st chunk --
for i in range(1024):
f.write('a')
# -- end of 2nd chunk
f.write('a')
with open(test_file) as f:
assert len(list(rows(f, chunksize=chunksize))) == 2
if __name__ == '__main__':
for chunksize in [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]:
test_empty(chunksize)
test_1_char_2_rows(chunksize)
test_1_char(chunksize)
test_1025_chars_1_row(chunksize)
test_1024_chars_2_rows(chunksize)
test_1025_chars_1026_rows(chunksize)
test_2048_chars_2_rows(chunksize)
test_2049_chars_2_rows(chunksize)
f = open('really_big_file.dat')
ist also nur ein Zeiger ohne Speicherverbrauch? (Ich meine, der verbrauchte Speicher ist unabhängig von der Dateigröße gleich?) Wie wirkt sich dies auf die Leistung aus, wenn ich urllib.readline () anstelle von f.readline () verwende?