估计文件中的行数 - 文件大小和所有行的大小不匹配

Posted

技术标签:

【中文标题】估计文件中的行数 - 文件大小和所有行的大小不匹配【英文标题】:estimating number of lines in a file - mismatch between file size and size of all lines 【发布时间】:2015-02-22 21:52:33 【问题描述】:

我有几百个文件,每个文件的大小在 10 到几 GB 之间,我想估计行数(即不需要精确计数)。每行都非常规则,例如 4 个长整数和 5 个双浮点数。

我试图找出文件中前AVE_OVER 行的平均大小,然后用它来估计总行数:

nums = sum(1 for line in open(files[0]))
print "Number of lines = ", nums

AVE_OVER = 10
lineSize = 0.0
count = 0
for line in open(files[0]):
    lineSize += sys.getsizeof(line)
    count += 1
    if( count >= AVE_OVER ): break

lineSize /= count
fileSize = os.path.getsize(files[0])
numLines = fileSize/lineSize
print "Estimated number of lines = ", numLines

估计差远了:

> Number of lines =  505235
> Estimated number of lines =  324604.165863

所以我尝试计算文件中所有行的总大小,与sys 测量的大小相比:

fileSize = os.path.getsize(files[0])
totalLineSize = 0.0
for line in open(files[0]):
totalLineSize += sys.getsizeof(line)

print "File size = %.3e" % (fileSize)
print "Total Line Size = %.3e" % (totalLineSize)

但这些又是不一致的!

> File size = 3.366e+07
> Total Line Size = 5.236e+07

为什么每行的大小总和比实际的总文件大小大得多?我该如何纠正这个问题?


编辑:我最终得到的算法(2.0版);感谢@J.F.Sebastian

def estimateLines(files):
    """ Estimate the number of lines in the given file(s) """

    if( not np.iterable(files) ): files = [files]
    LEARN_SIZE = 8192

    # Get total size of all files                                                                                                                                                                   
    numLines = sum( os.path.getsize(fil) for fil in files )

    with open(files[0], 'rb') as file:
         buf = file.read(LEARN_SIZE)
         numLines /= (len(buf) // buf.count(b'\n'))

    return numLines

【问题讨论】:

@OlehPrypin " \ Docstring: getsizeof(object, default) -> int \ 返回对象的字节大小。"是的,上帝,我太笨了,因为我没有直觉,这不会给我我正在看的物体的大小……我怎么会这么笨?!感谢您的反对。 line.count(b'\n')1(如果文件末尾没有换行符,则为 0)。不要一起使用for line in fileline.count(b'\n'):没用。使用其中一种。后者更快。 def estimateLines(filename): return os.path.getsize(filename) // line_size_hint(filename) @J.F.Sebastian 感谢您的反馈。我试图在前几行上实现平均值 --- 但现在我知道你的已经这样做了(嗯,最多 8192 字节)。 如果您想避免估计每个文件的行大小并使用基于第一个文件计算的行大小提示然后估计多个文件中的行数,您可以使用numLines = sum(map(os.path.getsize, files)) // line_size_hint(files[0]) 1) 删除if not np.iterable(files): files = [files]。它什么也不做,因为 str/unicode 实例是可迭代的(在 Python 2 中 open() 可以接受的类型)。您是否期望一个不可迭代但被open() 接受的(缓冲区)类型? 2) 使用//= 与 Python 3 兼容。3) 为什么不想将代码片段重构为 line_size_hint() 函数(函数调用开销应该与所有 I/O 相比可以忽略不计)? 4) 不要将answer(解决方案)放入问题中,而是将其作为答案发布。 【参考方案1】:

要估计文件中的行数:

def line_size_hint(filename, learn_size=1<<13):
    with open(filename, 'rb') as file:
        buf = file.read(learn_size)
        return len(buf) // buf.count(b'\n')

number_of_lines_approx = os.path.getsize(filename) // line_size_hint(filename)

要查找确切的行数,您可以use wc-l.py script:

#!/usr/bin/env python
import sys
from functools import partial

print(sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, 1 << 15), '')))

【讨论】:

【参考方案2】:

sys.getsizeof 是这里出现问题的唯一原因。它给出了依赖于实现的任意大小的对象,根本不应该使用,除了极少数情况。

只需将文件作为二进制文件打开,然后使用 len 获取行的实际长度。

【讨论】:

以上是关于估计文件中的行数 - 文件大小和所有行的大小不匹配的主要内容,如果未能解决你的问题,请参考以下文章

正则grep用法

grep命令

Linux. grep 命令

牛客Shell实战题目1~8

Linux grep

shell4