python读取大文件的几种方法

在python中,当我们读取一个本地TextIO文件时,最常用的方式是用readreadlinereadlines这三个方法。

fp.readlines()

with open(fp_name) as f_read:
    data = f_read.readlines()    # The type of data is a list.

# output:
# ["<?xml version='1.0' encoding='utf8'?>\n", ...]

这种方式是将文件里面所有内容按行读取到一个大列表中。对于小文件,这种方式其实挺方便,但对于大文件就会出现内存可能不足的情况,报MemoryError错误,或者消耗掉很客观的内存资源。

fp.readline()

# 第一种写法
with open(fp_name) as f_read:
    while True:
        line = f_read.readline()    # The type of line is a string.
        if not line:
            break

# 第二种写法
with open(fp_name) as f_read:
    for line in f_read:
        ...

上面两种写法本质其实一样,都是按行读取文本,这种方式读取文件会大大减少内存的消耗,一直读到空行或者EOF标识才会被终止。一般大场景读取文件这种方式性能和内存消耗比较好。

但这种方式也有一个缺陷,若文本是写在一行,而不是多行,那么这两种写法不论哪一种,都和前面两种方式一样,将所有的文本内容【一行字符串】加载到内存当中,消耗大量的资源。那么这个时候处理单行十分大的文件,使用fp.read()这个最为底层的方法更好一些。

fp.read()

with open(fp_name) as f_read:
    data = f_read.read()    # The type of data is a string.

# output
# '<?xml version=\'1.0\' encoding=\'utf8\'?>\n<OpenDRIVE><header revMajor="1" revMinor="4" name="" version="1.00" date="01/01/1970 17:45\n...\n'

不带参数的情况下,这种方式将文本内容读取为一个大的字符串对象,类似 readlines() 方法,只不过是输出数据的格式不同。如果文本比较大,该方式会消耗很客观的内存。

不过该方法有一个 size 参数,用于设置读取文本的字节数,每次调用 fp.read(size) 会直接返回从当前位置往后读取 size 大小的文件内容,不必等待任何换行符出现,这种方式有利于对单行大文本进行读取处理。

我们可以使用这个分块参数这么读取大文件,效果要比按行读取的方式在内存消耗上优化很多:

from functools import partial, wraps
from typing import TextIO, Callable


def chunked_file_reader(fp: TextIO, block_size: int=1024 * 8):
    for chunk in iter(partial(fp.read, block_size), ''):
        yield chunk


def read_file(file_path: str) -> int:
    count: int = 0
    with open(file_path) as f_read:
        for chunk in chunked_file_reader(f_read):
            count += 1
            print(chunk)
    return count

利用迭代器生成器构造一个可复用的分块读取方法,然后就可以方便的控制每次读取的字节大小,在内存的占用以及代码的执行性能上都会有不错的表现。

本作品采用《CC 协议》,转载必须注明作者和本文链接
Stay hungry, stay foolish.
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!