Sudah ada banyak jawaban bagus, tetapi jika seluruh file Anda berada pada satu baris dan Anda masih ingin memproses "baris" (sebagai lawan dari blok ukuran tetap), jawaban ini tidak akan membantu Anda.
99% dari waktu, adalah mungkin untuk memproses file baris demi baris. Kemudian, seperti yang disarankan dalam jawaban ini , Anda bisa menggunakan objek file itu sendiri sebagai lazy generator:
with open('big.csv') as f:
for line in f:
process(line)
Namun, saya pernah bertemu dengan file baris tunggal yang sangat besar (hampir), di mana pemisah baris sebenarnya tidak '\n'
tetapi '|'
.
- Membaca baris demi baris bukanlah pilihan, tetapi saya masih perlu memprosesnya baris demi baris.
- Konversi
'|'
ke '\n'
sebelum pemrosesan juga keluar dari pertanyaan, karena beberapa bidang csv ini berisi '\n'
(input pengguna teks gratis).
- Menggunakan perpustakaan csv juga dikesampingkan karena fakta bahwa, setidaknya dalam versi awal lib, hardcoded untuk membaca input baris demi baris .
Untuk situasi seperti ini, saya membuat cuplikan berikut:
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
Saya berhasil menggunakannya untuk menyelesaikan masalah saya. Ini telah diuji secara luas, dengan berbagai ukuran potongan.
Test suite, bagi mereka yang ingin meyakinkan diri mereka sendiri.
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')
hanyalah pointer tanpa konsumsi memori? (Maksud saya memori yang dikonsumsi sama terlepas dari ukuran file?) Bagaimana pengaruhnya terhadap kinerja jika saya menggunakan urllib.readline () dan bukannya f.readline ()?