python获取字符串⾏数_关于⽂本⽂件:如何在python中获取
⾏数?
我需要在python中获取⼀个⼤⽂件(数⼗万⾏)的⾏数。记忆和时间⽅⾯最有效的⽅法是什么?
现在我这样做了:
def file_len(fname):
with open(fname) as f:
for i, l in enumerate(f):
pass
return i + 1
有没有可能做得更好?
您需要精确的⾏数还是近似值就⾜够了?
我需要⼀个准确的。
mmap格式怎么打开使⽤核⼼卢克。
我会在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,因为我不会被初始化。
我不知道效率有多⾼,但adlines())看起来可读性更强。
@Riitek:那会读取整个⽂件,导致内存溢出…
我已经⽤熊猫做了⼀些测试,⽽且似乎快得多。ad_csv(file_name,header=none))。索引
将⽂件拆分为多个⽂件,并使⽤并⾏程序或Hadoop?
⼀⾏,可能很快:
num_lines = sum(1 for line in open(''))
不错,也适⽤于空⽂件。
它是如何⼯作的?
它类似于和(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代表打开的⾏(‘’)if line.rstrip())代表筛选空⾏
当我们打开⼀个⽂件时,⼀旦我们遍历了所有元素,它会⾃动关闭吗?是否需要"close()"?我认为我们不能在这个简短的语句中使⽤'with open()',对吗?
如果有⼀个解释解释为什么它起作⽤的话,那么对于那些抓住这个答案快速解决问题的⼈来说,这将是⾮常有益的。
@Mannaggia您是正确的,最好使⽤"with open(filename)"来确保⽂件在完成时关闭,并且最好在try-except块中执⾏此操作,如果⽆法打开⽂件,将引发和ioerror异常。
另⼀件需要注意的事情是:这⽐原始问题在30万⾏⽂本⽂件上给出的速度慢⼤约0.04-0.05秒。
@安德鲁,你确定你测试过……科学地?
如果使⽤枚举,则不需要求和。除⾮使⽤列表理解,否则计数将在for循环之后维护。对于num_⾏,u in enumerate(open("")):pass
你能解释⼀下这⾏1的作⽤吗?num_lines=sum(open("")中的⾏为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('')])?
你不会⽐这更好的。
毕竟,任何解决⽅案都必须读取整个⽂件,出您拥有多少,并返回该结果。
在不读取整个⽂件的情况下,您有更好的⽅法吗?不确定。。。最好的解决⽅案将始终是I/O绑定的,您所能做的最好的就是确保不使⽤不必要的内存,但看起来您已经覆盖了这⼀点。
准确地说,即使是wc也在读取⽂件,但在c中,它可能是相当优化的。
据我所知,python⽂件IO也是通过C完成的。/library/stdtypes.html⽂件对象
posix_fadvise()可以使⽤stackoverflow/questions/860893/…虽然我没有注意到任何改进
gist.github/0ac760859e614cd03652
@托马拉克那是条红鲱鱼。虽然python和wc可能发出相同的系统调⽤,但python有wc没有的操作码调度开销。
您可以通过采样估计⾏数。它可以快上千倍。参见:documentroot/2011/02/…
其他答案似乎表明这个分类答案是错误的,因此应该删除⽽不是保留为接受。
使⽤sum()⽅法的⽣成器或列表理解⽅法是否更快?
这个答案显然是错误的。请参阅glglgl的答案:stackoverflow/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 = ap(f.fileno(), 0)
lines = 0
readline = adline
while readline():
lines += 1
return lines
def simplecount(filename):
lines = 0
for line in open(filename):
lines += 1
return lines
def bufcount(filename):
f = open(filename)
lines = 0
buf_size = 1024 * 1024
read_f = f.read # loop optimization
buf = read_f(buf_size)
while buf:
lines += unt('
')
buf = read_f(buf_size)
return lines
def opcount(fname):
with open(fname) as f:
for i, l in enumerate(f):
pass
return i + 1
counts = defaultdict(list)
for i in range(5):
for func in [mapcount, simplecount, bufcount, opcount]:
start_time = time.time()
assert func("") == 1209138
counts[func].append(time.time() - start_time)
for key, vals in counts.items():
print key.__name__,":", sum(vals) / float(len(vals))
这很有趣,因为我看到了不同的数字。⽂件的实际⼤⼩(字节)?
⽂件⼤⼩为53064630字节。
正如我之前所说,bufcount在我的机器上速度⾮常慢(最多6次)。mapcount确实是最快的,仅次于wc-l解决⽅案
(stackoverflow/questions/845058/…)。我看到的唯⼀缺点是消耗了额外的100MB内存,这取决于您的设置可能是相当合适的。我认为你的回答应该得到⽀持:)
整个内存映射⽂件未加载到内存中。您得到⼀个虚拟内存空间,操作系统根据需要交换内存。以下是在Windows上处理它们的⽅法:msdn.microsoft/en-us/library/ms810613.aspx
抱歉,这⾥有⼀个关于内存映射⽂件的更⼀般的参考:/wiki/memory-mapped_file,感谢投票。:)
尽管它只是⼀个虚拟内存,但它正是限制这种⽅法的原因,因此对于⼤型⽂件来说,它将不起作⽤。我⽤~1.2 GB的⽂件尝试过,⽂件容量超过了1000万。⾏(通过wc-l获得)并得到⼀个windowserror:[错误8]没有⾜够的存储空间来处理此命令。当然,这是⼀个边缘案例。
+1⽤于实时数据。我们知道1024*1024的缓冲区⼤⼩是最佳的还是更好的?
似乎wccount()是最快的gist.github/0ac760859e614cd03652
我有疑问。当使⽤opcount()中的另⼀个函数call enumerate()时,opcount()⽐simpleCount()效率如何?
@rgk,python中的addition操作符相当昂贵:/但是请注意,两者之间的差别很⼩。
为什么⽤r+打开地图,不需要写访问!
我不得不把这个贴在⼀个类似的问题上,直到我的名誉分数跳了⼀点(多亏了撞我的⼈!).
所有这些解决⽅案都忽略了⼀种使运⾏速度⼤⼤加快的⽅法,即使⽤未缓冲(原始)接⼝、使⽤bytearray
和执⾏⾃⼰的缓冲。(这仅适⽤于python 3。在python 2中,原始接⼝在默认情况下可以使⽤,也可以不使⽤,但是在python 3中,您将默认为unicode。)
使⽤修改过的计时⼯具,我相信下⾯的代码⽐提供的任何解决⽅案都快(⽽且稍微多⼀些Python式的代码):
def rawcount(filename):
f = open(filename, 'rb')
lines = 0
buf_size = 1024 * 1024
read_f = ad
buf = read_f(buf_size)
while buf:
lines += unt(b'
')
buf = read_f(buf_size)
return lines
使⽤单独的⽣成器功能,运⾏速度更快:
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(ad)
return sum( unt(b'
') for buf in f_gen )
这完全可以通过使⽤itertools的内联⽣成器表达式来完成,但是看起来很奇怪:
from itertools import (takewhile,repeat)
def rawincount(filename):
f = open(filename, 'rb')
bufgen = takewhile(lambda x: x, (ad(1024*1024) for _ in repeat(None)))
return sum( unt(b'
') for buf in bufgen )
以下是我的时间安排:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。