在这里插入代码片
很久以前做数学建模的时候面临了一回大文件的读取问题,当时没有什么编程经验就使用如下的代码进行了读取。
with open(filename, 'rb') as fp:
for line in fp.readlines():
do_something(line)
这种代码在文件比较小时倒也没有太大影响,但是面临大文件时就无解了。
分析代码: (可以使用memory_profiler.profile函数对代码的内存使用进行分析,这里使用了装饰器)
from memory_profiler import profile
@profile
def func(filename):
with open(filename, 'rb') as fp:
for line in fp.readlines():
#do_something(line)
pass
if __name__ == '__main__':
func('test_file')
得到如下结果
Line # Mem usage Increment Line Contents
================================================
35 16.1 MiB 16.1 MiB @profile
36 def func(filename):
37 16.1 MiB 0.0 MiB with open(filename, 'rb') as fp:
38 18.6 MiB 2.5 MiB for line in fp.readlines():
39 #do_something(line)
40 18.6 MiB 0.0 MiB pass
这样就“成功”把文件全部加载进内存了。 【捂脸】
后面获得了好友的点播,我也知道了优化方法了。
按行读取
wiht open('test_file', 'rb') as fp:
for line in fp: # 这里将fp文件对象作为一个可迭代对象进行迭代
# do something with line
pass
读取固定大小
with open('test_file', 'rb') as fp:
while True:
buf = fp.read(BATCH_SIZE)
if buf:
# do something with buf
pass
else:
break
实现文件读取的滑动窗口
通过文件光标的移动实现
def window_read(filename):
with open(filename, 'rb') as fp:
file_size = os.path.getsize(filename)
while True:
buf = fp.read(100)
if buf:
print(buf)
if fp.tell()== file_size:
break
else:
fp.seek(-20,1)
else:
break
内存使用结果:
Line # Mem usage Increment Line Contents
================================================
4 16.1 MiB 16.1 MiB @profile
5 def window_read(filename):
6 16.1 MiB 0.0 MiB with open(filename, 'rb') as fp:
7 16.1 MiB 0.0 MiB file_size = os.path.getsize(filename)
8 16.1 MiB 0.0 MiB while True:
9 16.1 MiB 0.0 MiB buf = fp.read(100)
10 16.1 MiB 0.0 MiB if buf:
11 16.1 MiB 0.0 MiB print(buf)
12 16.1 MiB 0.0 MiB if fp.tell()== file_size:
13 16.1 MiB 0.0 MiB break
14 else:
15 16.1 MiB 0.0 MiB fp.seek(-20,1)
16 else:
17 break