小编典典

Python最快访问文件中的行

python

我在文件中有一个ASCII表,我想从中读取一组特定的行(例如,4003至4005行)。问题是该文件可能非常长(例如,十万到几百万行),我想尽快这样做。

错误的解决方案 :读取整个文件,然后转到这些行,

f = open('filename')
lines = f.readlines()[4003:4005]

更好的解决方案 enumerate遍历每行,以便不将其全部存储在内存中http://codingdict.com/questions/775

f = open('filename')
lines = []
for i, line in enumerate(f):
    if i >= 4003 and i <= 4005: lines.append(line)
    if i > 4005: break                                    # @Wooble

最佳解决方案?

但这仍然需要遍历每一行。是否有更好的(从速度/效率方面)访问特定线路的方法?即使我只会访问一次文件(通常),也应该使用线缓存吗?

使用二进制文件代替,在这种情况下,跳过可能更容易,这是一个选项—但我宁愿避免使用它。


阅读 211

收藏
2020-12-20

共1个答案

小编典典

我可能只会使用itertools.islice。在像文件句柄这样的可迭代对象上使用islice意味着永远不会将整个文件读入内存,并且尽可能快地丢弃前4002行。您甚至可以非常便宜地将所需的两行转换为列表(假设这两行本身不太长)。然后,您可以退出该with块,关闭文件句柄。

from itertools import islice
with open('afile') as f:
    lines = list(islice(f, 4003, 4005))
do_something_with(lines)

更新资料

但是,圣牛的行缓存速度更快,可以进行多次访问。我创建了一个百万行的文件来比较islice和linecache,然后将其删除。

>>> timeit("x=islice(open('afile'), 4003, 4005); print next(x) + next(x)", 'from itertools import islice', number=1)
4003
4004

0.00028586387634277344
>>> timeit("print getline('afile', 4003) + getline('afile', 4004)", 'from linecache import getline', number=1)
4002
4003

2.193450927734375e-05

>>> timeit("getline('afile', 4003) + getline('afile', 4004)", 'from linecache import getline', number=10**5)
0.14125394821166992
>>> timeit("''.join(islice(open('afile'), 4003, 4005))", 'from itertools import islice', number=10**5)
14.732316970825195

不断重新导入和重新读取文件:

这不是一个实际的测试,但是即使在每个步骤中重新导入线缓存,也只比islice慢一秒钟。

>>> timeit("from linecache import getline; getline('afile', 4003) + getline('afile', 4004)", number=10**5)
15.613967180252075

结论

是的,对于所有缓存,linecache的速度都比islice快,但它会不断地重新创建linecache,但是谁来做呢?对于可能的情况(一次仅读取几行,一次读取多行),行缓存速度更快,并且呈现简洁的语法,但是该islice语法也非常干净快捷,并且永远不会将整个文件读入内存。在RAM密集型环境中,islice解决方案可能是正确的选择。对于非常高的速度要求,行缓存可能是更好的选择。但是实际上,在大多数环境中,两次时间都足够小,几乎没有关系。

2020-12-20