首推with open( )

其实之前有很长一段时间不知道with open()的神奇作用,直到这次遇到问题,才发现它的奇妙之处。原来python中用with语句打开和关闭文件,包括了抛出一个内部块异常,并且,for line in f其实是将文件对象f视为一个迭代器,自动的采用缓冲IO和内存管理,所以不必担心大文件。让系统来处理,其实是最简单的方式,交给解释器,就万事大吉了。

1
2
3
4
5
#If the file is line based
# "rb"速度可能会加快
with open('...','r') as f:
    for line in f:
        process(line) # 

Read In Chunks

这是正常情况下大家都会想到的办法,就是将大文件分割成若干小文件处理,处理完每个小文件后释放该部分内存。可以参照之前的这篇文《python提高读文件效率》

https://github.com/Shuang0420/Shuang0420.github.io/wiki/python%E6%8F%90%E9%AB%98%E8%AF%BB%E6%96%87%E4%BB%B6%E6%95%88%E7%8E%87

代码如下

1
2
3
4
5
6
7
file = open("sample.txt")
while 1:
    lines = file.readlines(100000)
    if not lines:
        break
    for line in lines:
        pass # do something

或者

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def read_in_chunks(filePath, chunk_size=1024*1024):
    """
    Lazy function (generator) to read a file piece by piece.
    Default chunk size: 1M
    You can set your own chunk size 
    """
    file_object = open(filePath)
    while True:
        chunk_data = file_object.read(chunk_size)
        if not chunk_data:
            break
        yield chunk_data
if __name__ == "__main__":
    filePath = './path/filename'
    for chunk in read_in_chunks(filePath):
        process(chunk) # 

顺便提一下我遇到的问题,因为后面测试需要,我将读取的文件按行存到了list里面,memory使用率一路飙升过50%,这真是作死的节奏……之后我取了前500行做测试,memory始终稳定保持在3.5%,问题解决。

参考链接 http://chenqx.github.io/2014/10/29/Python-fastest-way-to-read-a-large-file/

下面这个方法虽然快,但是每次是读一定数量的字符,主要应用于没有换行符的文本。此方法用于有换行符的文件时,可以使用split("\n")的方法提取内容,但是可能要涉及拼接,上一个chunk的末尾拼接下一个chunk的开头

1
2
3
4
5
6
7
8
from functools import partial
def chunked_file_reader(file, block_size=1024 * 8):
    """生成器函数:分块读取文件内容,使用 iter 函数
    """
    # 首先使用 partial(fp.read, block_size) 构造一个新的无需参数的函数
    # 循环将不断返回 fp.read(block_size) 调用结果,直到其为 '' 时终止
    for chunk in iter(partial(file.read, block_size), ''):
        yield chunk

One useful application of the second form of iter() is to build a block-reader. For example, reading fixed-width blocks from a binary database file until the end of file is reached:

1
2
3
4
5
# https://docs.python.org/3/library/functions.html
from functools import partial
with open('mydata.db', 'rb') as f:
    for block in iter(partial(f.read, 64), b''):
        process_block(block)

Reference

1、 https://github.com/Shuang0420/Shuang0420.github.io/wiki/python%E8%AF%BBGB%E7%BA%A7%E5%A4%A7%E6%96%87%E4%BB%B6
2、 https://v3u.cn/a_id_97

打赏

微信 微信 支付宝 支付宝
万分感谢