มีคำตอบที่ดีอยู่แล้วจำนวนมาก แต่หากไฟล์ทั้งหมดของคุณอยู่ในบรรทัดเดียวและคุณยังต้องการประมวลผล "แถว" (ตรงข้ามกับบล็อกขนาดคงที่) คำตอบเหล่านี้จะไม่ช่วยคุณ
99% ของเวลาเป็นไปได้ที่จะประมวลผลไฟล์แบบทีละบรรทัด จากนั้นตามคำแนะนำในคำตอบนี้คุณสามารถใช้วัตถุไฟล์เป็นเครื่องมือสร้างสันหลังยาว:
with open('big.csv') as f:
for line in f:
process(line)
แต่ผมเคยวิ่งเข้ามากใหญ่มาก (เกือบ) ไฟล์บรรทัดเดียวที่คั่นแถวในความเป็นจริงไม่ได้แต่'\n'
'|'
- การอ่านทีละบรรทัดไม่ใช่ตัวเลือก แต่ฉันยังต้องดำเนินการทีละบรรทัด
- การแปลง
'|'
ไป'\n'
ก่อนการประมวลผลนั้นไม่เป็นไปตามคำถามเช่นกันเนื่องจากบางฟิลด์ของ csv นี้มีอยู่'\n'
(อินพุตผู้ใช้แบบข้อความอิสระ)
- การใช้ห้องสมุด CSV ก็ยังตัดออกไปเพราะความจริงที่ว่าอย่างน้อยในรุ่นแรกของ lib ที่มันเป็น hardcoded อ่านบรรทัดการป้อนข้อมูลโดยสาย
สำหรับสถานการณ์ประเภทนี้ฉันได้สร้างตัวอย่างต่อไปนี้:
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
ฉันสามารถใช้มันได้สำเร็จเพื่อแก้ปัญหาของฉัน มันได้รับการทดสอบอย่างกว้างขวางด้วยขนาดก้อนต่างๆ
ชุดทดสอบสำหรับผู้ที่ต้องการโน้มน้าวใจตัวเอง
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')
จึงเป็นเพียงตัวชี้โดยไม่มีการใช้หน่วยความจำใด ๆ (ฉันหมายถึงหน่วยความจำที่ใช้เหมือนกันโดยไม่คำนึงถึงขนาดของไฟล์?) จะมีผลต่อประสิทธิภาพการทำงานอย่างไรหากฉันใช้ urllib.readline () แทนที่จะเป็น f.readline ()