首页 > Python基础教程 >
-
Python读取大文件的"坑“与内存占用检测
python读写文件的api都很简单,一不留神就容易踩”坑“。笔者记录一次踩坑历程,并且给了一些总结,希望到大家在使用python的过程之中,能够避免一些可能产生隐患的代码。
1.read()与readlines()
随手搜索python读写文件的教程,很经常看到read()与readlines()这对函数。所以我们会常常看到如下代码:
1
2
3
4
5
6
|
with open (file_path, 'rb' ) as f: sha1Obj.update(f.read()) or with open (file_path, 'rb' ) as f: for line in f.readlines(): print (line) |
这对方法在读取小文件时确实不会产生什么异常,但是一旦读取大文件,很容易会产生MemoryError,也就是内存溢出的问题。
####Why Memory Error?
我们首先来看看这两个方法:
当默认参数size=-1时,read方法会读取直到EOF,当文件大小大于可用内存时,自然会发生内存溢出的错误。
read方法
read([size])方法从文件当前位置起读取size个字节,若无参数size,则表示读取至文件结束为止,它范围为字符串对象
同样的,readlines会构造一个list。list而不是iter,所以所有的内容都会保存在内存之上,同样也会发生内存溢出的错误。
readlines方法
该方法每次读出一行内容,所以,读取时占用内存小,比较适合大文件,该方法返回一个字符串对象。
2.正确的用法
在实际运行的系统之中如果写出上述代码是十分危险的,这种”坑“十分隐蔽。所以接下来我们来了解一下正确用,正确的用法也很简单,依照API之中对函数的描述来进行对应的编码就OK了:
如果是二进制文件推荐用如下这种写法,可以自己指定缓冲区有多少byte。显然缓冲区越大,读取速度越快。
1
2
3
4
5
6
7
|
with open (file_path, 'rb' ) as f: while True : buf = f.read( 1024 ) if buf: sha1Obj.update(buf) else : break |
而如果是文本文件,则可以用readline方法或直接迭代文件(python这里封装了一个语法糖,二者的内生逻辑一致,不过显然迭代文件的写法更pythonic )每次读取一行,效率是比较低的。笔者简单测试了一下,在3G文件之下,大概性能和前者差了20%.
1
2
3
4
5
6
7
8
9
10
|
with open (file_path, 'rb' ) as f: while True : line = f.readline() if buf: print (line) else : break with open (file_path, 'rb' ) as f: for line in f: print (line) |