我现在有一个非常简单的脚本,使用enumerate()
计算文本文件中的行:
i = 0
f = open("C:/Users/guest/Desktop/file.log", "r")
for i, line in enumerate(f):
pass
print i + 1
f.close()
这需要大约3分半钟才能完成大约3000万行的15GB日志文件。如果我能在两分钟或更短的时间内得到它,那将是很好的,因为这些是每日日志,我们想要进行每月分析,因此代码必须处理30个~15GB的日志 - 可能超过一个半小时,我们希望尽量减少时间和时间。服务器上的内存负载。
我也会接受一个好的近似/估计方法,但它需要大约4 sig fig准确...
谢谢!
答案 0 :(得分:24)
Ignacio's answer是正确的,但如果你有32位进程可能会失败。
但也许以块为单位读取文件然后计算每个块中的\n
个字符可能很有用。
def blocks(files, size=65536):
while True:
b = files.read(size)
if not b: break
yield b
with open("file", "r") as f:
print sum(bl.count("\n") for bl in blocks(f))
将完成你的工作。
请注意,我不会将文件打开为二进制文件,因此\r\n
将转换为\n
,从而使计数更可靠。
对于Python 3,并使其更加健壮,用于读取具有各种字符的文件:
def blocks(files, size=65536):
while True:
b = files.read(size)
if not b: break
yield b
with open("file", "r",encoding="utf-8",errors='ignore') as f:
print (sum(bl.count("\n") for bl in blocks(f)))
答案 1 :(得分:7)
我知道它有点不公平,但你可以这样做
int(subprocess.check_output("wc -l C:\\alarm.bat").split()[0])
如果您使用的是Windows,请查看Coreutils。
答案 2 :(得分:5)
快速的1行解决方案是:
sum(1 for i in open(file_path, 'rb'))
它应该适用于任意大小的文件。
答案 3 :(得分:4)
mmap该文件,并计算新行。
答案 4 :(得分:1)
我会扩展gl的答案并使用多处理Python模块运行他/她的代码以便更快地计算:
def blocks(f, cut, size=64*1024): # 65536
start, chunk =cut
iter=0
read_size=int(size)
_break =False
while not _break:
if _break: break
if f.tell()+size>start+chunk:
read_size=int(start+chunk- f.tell() )
_break=True
b = f.read(read_size)
iter +=1
if not b: break
yield b
def get_chunk_line_count(data):
fn, chunk_id, cut = data
start, chunk =cut
cnt =0
last_bl=None
with open(fn, "r") as f:
if 0:
f.seek(start)
bl = f.read(chunk)
cnt= bl.count('\n')
else:
f.seek(start)
for i, bl in enumerate(blocks(f,cut)):
cnt += bl.count('\n')
last_bl=bl
if not last_bl.endswith('\n'):
cnt -=1
return cnt
....
pool = multiprocessing.Pool(processes=pool_size,
initializer=start_process,
)
pool_outputs = pool.map(get_chunk_line_count, inputs)
pool.close() # no more tasks
pool.join()
这将使计数性能提高20倍。 我把它包裹到script并把它放到Github。