(蟒蛇)尽可能快地计算大型 (>10GB) 文件中的行数



我现在有一个非常简单的脚本,它使用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分钟半的时间来浏览一个15GB的日志文件,其中大约有3000万行。如果我能在两分钟或更短的时间内完成这项工作,那就太好了,因为这些都是每日日志,我们想每月进行一次分析,所以代码必须处理30个15GB的日志,可能超过一个半小时,我们希望尽量减少时间;服务器上的内存负载。

我也会选择一个好的近似/估计方法,但它需要大约4西格的准确度。。。

谢谢!

Ignacio的答案是正确的,但如果您有一个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))

会做好你的工作。

请注意,我没有以二进制文件的形式打开该文件,因此rn将转换为n,从而使计数更加可靠。

对于Python3,为了使其更加健壮,用于读取具有各种字符的文件:

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)))

我知道这有点不公平,但你可以这样做

int(subprocess.check_output("wc -l C:\alarm.bat").split()[0])

如果您使用的是Windows,请查看Coreutils。

一个快速的单线解决方案是:

sum(1 for i in open(file_path, 'rb'))

它应该适用于任意大小的文件。

mmap文件,并计算换行数。

import mmap
def mapcount(filename):
    with open(filename, "r+") as f:
        buf = mmap.mmap(f.fileno(), 0)
        lines = 0
        readline = buf.readline
        while readline():
            lines += 1
        return lines

我会扩展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倍。我把它包装成一个脚本,然后放到Github上。

相关内容

  • 没有找到相关文章

最新更新