如何逐行读取大文件?
我想要逐行读取整个文件。有一种方法是先把整个文件读进来,存到一个列表里,然后再逐行处理。这种方法会占用很多内存,所以我在找其他的办法。
我目前的代码是:
for each_line in fileinput.input(input_file):
do_something(each_line)
for each_line_again in fileinput.input(input_file):
do_something(each_line_again)
运行这段代码时出现了一个错误信息:device active
。
有什么建议吗?
我的目的是计算字符串之间的相似度,也就是说,对于文件中的每一行,我想要计算它与其他每一行的Levenshtein距离。
2022年11月更新:在这个问题提出8个月后,有一个相关的问题得到了很多有用的回答和评论。为了更深入地理解Python的逻辑,也可以看看这个相关的问题 如何在Python中逐行读取文件?
11 个回答
去掉换行符:
with open(file_path, 'rU') as f:
for line_terminated in f:
line = line_terminated.rstrip('\n')
...
使用 通用换行符支持,所有文本文件的行都会被视为以 '\n'
结束,无论文件中的换行符是 '\r'
、'\n'
还是 '\r\n'
。
编辑 - 如何指定通用换行符支持:
- 在Unix系统上的Python 2 -
open(file_path, mode='rU')
- 是必须的 [感谢 @Dave] - 在Windows上的Python 2 -
open(file_path, mode='rU')
- 是可选的 - Python 3 -
open(file_path, newline=None)
- 是可选的
newline
参数仅在Python 3中支持,默认值是 None
,这表示使用通用换行模式(输入文件可以有任何换行符,输出字符串会变成 \n
)。在所有情况下,mode
参数的默认值是 'r'
。在Python 3中,U
已被弃用。在Windows上的Python 2中,似乎有其他机制将 \r\n
转换为 \n
。
文档:
保留原生行结束符:
with open(file_path, 'rb') as f:
with line_native_terminated in f:
...
使用二进制模式仍然可以将文件解析为行,使用 in
。每一行会保留文件中的原始换行符。
感谢 @katrielalex 的 回答、Python 的 open() 文档,以及 iPython 的实验。
这里有两种节省内存的方法,按效果排序(第一种最好) -
- 使用
with
- 从 Python 2.5 及以上版本支持 - 使用
yield
如果你想更好地控制每次读取多少内容
1. 使用 with
with
是一种很方便且高效的方式来读取大文件。它的优点有:1)在退出 with
代码块后,文件对象会自动关闭。2)可以在 with
块内处理异常。3)内存中的 for
循环可以逐行遍历 f
文件对象。它内部会进行缓冲输入输出(这样可以优化昂贵的输入输出操作)和内存管理。
with open("x.txt") as f:
for line in f:
do something with data
2. 使用 yield
有时候你可能想要更精细地控制每次读取多少内容。在这种情况下,可以使用 iter 和 yield。需要注意的是,使用这种方法时,最后需要手动关闭文件。
def readInChunks(fileObj, chunkSize=2048):
"""
Lazy function to read a file piece by piece.
Default chunk size: 2kB.
"""
while True:
data = fileObj.read(chunkSize)
if not data:
break
yield data
f = open('bigFile')
for chunk in readInChunks(f):
do_something(chunk)
f.close()
注意事项和补充说明 - 以下方法在读取大文件时效果不如前面提到的两种方法,但了解它们有助于全面理解。
在 Python 中,读取文件行的最常见方法是这样做:
for line in open('myfile','r').readlines():
do_something(line)
然而,当这样做时,readlines()
函数(read()
函数也是如此)会将整个文件加载到内存中,然后再进行遍历。对于大文件来说,稍微好一点的方法(前面提到的两种方法是最好的)是使用 fileinput
模块,如下所示:
import fileinput
for line in fileinput.input(['myfile']):
do_something(line)
fileinput.input()
调用会顺序读取行,但在读取后不会将它们保留在内存中,或者说因为 file
在 Python 中是可迭代的,所以这样做也可以。
参考资料
用Python读取文件的正确方法是这样的:
with open(...) as f:
for line in f:
# Do something with 'line'
这里的with
语句负责打开和关闭文件,即使在内部代码出错的情况下也能处理好。for line in f
把文件对象f
当作一个可迭代的对象,这样就能自动使用缓冲输入输出和内存管理,所以你不用担心处理大文件的问题。
应该有一种——最好只有一种——明显的方法来做到这一点。