import subprocess
def count_file_lines(file_path):
"""
Counts the number of lines in a file using wc utility.
:param file_path: path to file
:return: int, no of lines
"""
num = subprocess.check_output(['wc', '-l', file_path])
num = num.split(' ')
return int(num[0])
def _make_gen(reader):
b = reader(1024 * 1024)
while b:
yield b
b = reader(1024*1024)
def rawgencount(filename):
f = open(filename, 'rb')
f_gen = _make_gen(f.raw.read)
return sum( buf.count(b'\n') for buf in f_gen )
这可以使用itertools在线生成器表达式完全完成,但它看起来非常奇怪:
from itertools import (takewhile,repeat)
def rawincount(filename):
f = open(filename, 'rb')
bufgen = takewhile(lambda x: x, (f.raw.read(1024*1024) for _ in repeat(None)))
return sum( buf.count(b'\n') for buf in bufgen )
In [20]: timeit sum(1 for line in open('Charts.ipynb'))
100000 loops, best of 3: 9.79 µs per loop
In [21]: timeit len(open('Charts.ipynb').read().splitlines())
100000 loops, best of 3: 12 µs per loop
30 回答
同理:
另一种可能性
我会使用Python的文件对象方法
readlines
,如下所示:这将打开文件,在文件中创建行列表,计算列表的长度,将其保存到变量并再次关闭文件 .
打开文件的结果是一个迭代器,它可以转换为一个序列,其长度为:
这比显式循环更简洁,并避免使用
enumerate
.一线解决方案
我的片段
为什么不读取前100行和后100行并估计平均行长,然后将总文件大小除以这些数字?如果您不需要确切的值,这可能会起作用 .
这是一个python程序,它使用多处理库来分配跨机器/核心的行计数 . 我的测试使用8核Windows 64服务器改进了计算2000万行文件的时间从26秒到7秒 . 注意:不使用内存映射会使事情变得更慢 .
此代码更短更清晰 . 这可能是最好的方式:
我使用这个版本获得了一个小的(4-8%)改进,它重新使用了一个常量缓冲区,所以它应该避免任何内存或GC开销:
您可以使用缓冲区大小,也许可以看到一些改进 .
我相信内存映射文件将是最快的解决方案 . 我尝试了四个函数:OP发布的函数(
opcount
);对文件中的行进行简单迭代(simplecount
);带有内存映射字段(mmap)的readline(mapcount
);以及Mykola Kharechko(bufcount
)提供的缓冲读取解决方案 .我运行了五次每个函数,并计算了一个120万行文本文件的平均运行时间 .
Windows XP,Python 2.5,2GB RAM,2 GHz AMD处理器
这是我的结果:
Edit :Python 2.6的数字:
因此缓冲区读取策略似乎是Windows / Python 2.6中最快的
这是代码:
我修改了这样的缓冲区:
现在也是空文件,最后一行(没有\ n)被计算在内 .
这是我用的,看起来很干净:
更新:这比使用纯python略快,但代价是内存使用 . 在执行命令时,子进程将使用与父进程相同的内存占用分叉新进程 .
如果有人想在Linux中用Python来廉价地获得行数,我推荐这种方法:
file_path既可以是抽象文件路径,也可以是相对路径 . 希望这可能有所帮助 .
至于我,这个变种将是最快的:
原因:缓冲比逐行读取更快,
string.count
也非常快这个单行怎么样:
使用此方法花费0.003秒将其计时在3900行文件上
这个怎么样?
你不能比这更好 .
毕竟,任何解决方案都必须读取整个文件,找出你有多少
\n
并返回结果 .如果不阅读整个文件,你有更好的方法吗?不确定......最好的解决方案永远都是I / O绑定的,你能做的最好就是确保你不要使用不必要的内存,但看起来你已经覆盖了它 .
那这个呢
这是我用纯python发现的最快的东西 . 您可以通过设置缓冲区来使用任何数量的内存,但2 ** 16似乎是我计算机上的最佳位置 .
我在这里找到了答案Why is reading lines from stdin much slower in C++ than Python?并稍微调整了一下 . 这是一个非常好的阅读,以了解如何快速计算线,虽然
wc -l
仍然比其他任何东西快75% .一行,可能很快:
我不得不在类似的问题上发布这个问题,直到我的声望得分有所提高(感谢任何撞到我的人!) .
所有这些解决方案都忽略了一种方法,使运行速度更快,即使用无缓冲(原始)接口,使用字节数组,并进行自己的缓冲 . (这仅适用于Python 3.在Python 2中,默认情况下可能使用或不使用原始接口,但在Python 3中,您将默认使用Unicode . )
使用修改版的计时工具,我相信以下代码比任何提供的解决方案更快(并且更加pythonic):
使用单独的生成器函数,可以更快地运行:
这可以使用itertools在线生成器表达式完全完成,但它看起来非常奇怪:
这是我的时间:
Kyle's answer
可能是最好的,另一种选择是
以下是两者表现的比较
一个类似于this answer的单行bash解决方案,使用现代
subprocess.check_output
函数:你可以执行一个子进程并运行
wc -l filename
只是为了完成上述方法,我尝试了一个带有fileinput模块的变体:
并将60mil行文件传递给上述所有方法:
对我来说有点意外的是,fileinput很糟糕,并且比其他所有方法都要糟糕得多......
count = max(enumerate(open(filename)))[0]