我需要在python中获取一个大文件(数十万行)的行数。记忆和时间方面最有效的方法是什么?
现在我这样做了:
def file_len(fname):
with open(fname) as f:
for i, l in enumerate(f):
pass
return i + 1
有没有可能做得更好?
您需要精确的行数还是近似值就足够了?
我需要一个准确的。
使用核心卢克。
我会在for循环之前添加i=-1,因为此代码不适用于空文件。
@传说:我打赌皮科在想,得到文件大小(使用seek(0,2)或equiv),除以大约的行长。你可以在开头读几行来猜测平均行长。
enumerate(f, 1)和Ditch the i + 1?
@ianmackinnon适用于空文件,但在for循环之前必须将i初始化为0。
下面还有另一个(更好的)答案。是否要重新考虑移动勾号?
相关:为什么从STDIN到C++的读行要比Python慢得多?.见此处与wc-l.py的比较。
我最初是想找到一种快速的方法来预先分配一个存储为文本的表。但是,在我的例子中,我发现将值附加到列表(允许列表动态增长)比读取文件两次更快。根据您的I/O速度,这可能是需要考虑的问题。
有更好的方法,不会改变太多。将"r"标志添加到open函数中,这样它就不必自动找出要使用的标志。我对它进行了计时,该方法在没有"r"标志的情况下慢了约0.01秒。
您可以考虑使用终端并运行wc-l yourfilename
您需要首先检查文件是否存在。这可以使用os.path.isfile(fname)完成。我假设fname是完整的路径。然后在用open调用之前,将i初始化为-1。否则,如果文件是空的,您将得到一个unboundlocalerror,因为我不会被初始化。
我不知道效率有多高,但len(f.readlines())看起来可读性更强。
@Riitek:那会读取整个文件,导致内存溢出…
我已经用熊猫做了一些测试,而且似乎快得多。len(pd.read_csv(file_name,header=none))。索引
将文件拆分为多个文件,并使用并行程序或Hadoop?
一行,可能很快:
num_lines = sum(1 for line in open('myfile.txt'))
不错,也适用于空文件。
它是如何工作的?
它类似于和(1的序列),每行都计为1。>>>[1 for line in range(10)][1,1,1,1,1,1,1,1,1]>>>sum(1 for line in range(10))10>>>
num_lines=sum(1代表打开的行(‘myfile.txt’)if line.rstrip())代表筛选空行
当我们打开一个文件时,一旦我们遍历了所有元素,它会自动关闭吗?是否需要"close()"?我认为我们不能在这个简短的语句中使用'with open()',对吗?
如果有一个解释解释为什么它起作用的话,那么对于那些抓住这个答案快速解决问题的人来说,这将是非常有益的。
@Mannaggia您是正确的,最好使用"with open(filename)"来确保文件在完成时关闭,并且最好在try-except块中执行此操作,如果无法打开文件,将引发和ioerror异常。
另一件需要注意的事情是:这比原始问题在30万行文本文件上给出的速度慢大约0.04-0.05秒。
@安德鲁,你确定你测试过……科学地?
如果使用枚举,则不需要求和。除非使用列表理解,否则计数将在for循环之后维护。对于num_行,u in enumerate(open("file.txt")):pass
你能解释一下这行1的作用吗?num_lines=sum(open("myfile.txt")中的行为1)……(这里还是初学者)您能解释一下这行代码是如何计算文件中的行数的吗?我不知道"1"是什么,它是用来干什么的?谢谢
@stryker 1 for line in open(..)基本上为每条线路提供了1的列表(但不是因为它是一个生成器)。因此,如果文本文件包含三行,那么[1 for line in open(...)]将是[1, 1, 1]:对于每行,1将添加到数组中。然后将该列表传递给sum(),后者汇总迭代器内的所有值。所以sum([1,2,3])就是6。在前面的例子中,文本有三行,我们得到了一个[1,1,1]的列表。当求和时,得到3,这当然是行数。这似乎是多余的,但它的内存很便宜。
"可能很快"。代码越少并不意味着代码效率越高。
我们用len()代替sum()怎么样,比如len([l for l in open('myfile.txt')])?
你不会比这更好的。
毕竟,任何解决方案都必须读取整个文件,找出您拥有多少,并返回该结果。
在不读取整个文件的情况下,您有更好的方法吗?不确定。。。最好的解决方案将始终是I/O绑定的,您所能做的最好的就是确保不使用不必要的内存,但看起来您已经覆盖了这一点。
准确地说,即使是wc也在读取文件,但在c中,它可能是相当优化的。
据我所知,python文件IO也是通过C完成的。docs.python.org/library/stdtypes.html文件对象
posix_fadvise()可以使用stackoverflow.com/questions/860893/…虽然我没有注意到任何改进gist.github.com/0ac760859e614cd03652
@托马拉克那是条红鲱鱼。虽然python和wc可能发出相同的系统调用,但python有wc没有的操作码调度开销。
您可以通过采样估计行数。它可以快上千倍。参见:documentroot.com/2011/02/…
其他答案似乎表明这个分类答案是错误的,因此应该删除而不是保留为接受。
使用sum()方法的生成器或列表理解方法是否更快?
这个答案显然是错误的。请参阅glglgl的答案:stackoverflow.com/a/9631635/217802
简直不真实。找线就是找新线。您可以并行读取文件块,并搜索换行符,例如,通过让多个进程搜索内存映射文件的区域。
我相信内存映射文件将是最快的解决方案。我尝试了四个函数:op发布的函数(opcount);对文件中的行进行简单迭代(simplecount;使用内存映射文件的readline(mmap)(mapcount;以及mykola kharechko提供的缓冲区读取解决方案(bufcount)。
我运行了五次每个函数,并计算了120万行文本文件的平均运行时间。
Windows XP、python 2.5、2GB RAM、2 GHz AMD处理器
以下是我的结果:
mapcount : 0.465599966049
simplecount : 0.756399965286
bufcount : 0.546800041199
opcount : 0.718600034714
编辑:python 2.6的数字:
mapcount : 0.471799945831
simplecount : 0.634400033951
bufcount : 0.468800067902
opcount : 0.602999973297
因此,对于Windows/python 2.6来说,缓冲区读取策略似乎是最快的。
代码如下:
from __future__ import with_statement
import time
import mmap
import random
from collections import defaultdict
def mapcount(filename):
f = open(filename,"r+")
buf = mmap.mmap(f.fileno(), 0)
lines = 0
readline = buf.readline
while readline():
lines += 1
return lines
def simplecount(filename):
lines =