【问题标题】:Fastest way to count number of lines?计算行数的最快方法?
【发布时间】:2014-06-25 11:55:10
【问题描述】:

计算文件中行号的最简单方法是:

while(!feof(fp))
{
  ch = fgetc(fp);
  if(ch == '\n')
  {
    lines++;
  }
}

但现在的要求是我必须计算大文件中的行数。它会对性能产生影响。

有更好的方法吗?

【问题讨论】:

  • 是什么让您认为处理是瓶颈?
  • 因为这个代码在我的项目中经常被命中。
  • I/O 将占用大部分时间。
  • 这是纯粹的 IO 限制。如果您在计算行数时还有其他事情要做:考虑使用异步 IO 来提高性能。

标签: c


【解决方案1】:

对于最快的 I/O,您通常希望以文件系统/操作系统的 块大小 的倍数进行读取/写入。

您可以通过在文件或文件描述符上调用 statfs 或 fstatfs 来查询块大小(阅读手册页)。

struct statfs 有一个字段f_bsize,有时还有f_iosize:

最佳传输块大小

f_bsize 字段存在于所有 POSIX 系统上,AFAIK。在 Mac OS X 和 iOS 上,还有f_iosize,这是您在这些平台上更喜欢的那个(但f_bsize 也适用于 Mac OS X/iOS,通常应该与 f_iosize,IIRC 相同)。

struct statfs fsInfo = {0};
int fd = fileno(fp); // Get file descriptor from FILE*.
long optimalSize;

if (fstatfs(fd, &fsInfo) == -1) {
    // Querying failed! Fall back to a sane value, for example 8kB or 4MB.
    optimalSize = 4 * 1024 * 1024;
} else {
    optimalSize = fsInfo.f_bsize;
}

现在分配该大小的缓冲区并读取(使用read 或fread)该大小的块。然后迭代这个内存块并计算换行符的数量。重复直到 EOF。

另一种方法是@Ioan 提出的方法:使用mmap 将文件映射到内存并迭代该缓冲区。这可能会为您提供最佳性能,因为内核可以以最有效的方式读取数据,但是this might fail for files that are "too large" 虽然我上面描述的方法始终适用于任意大小的文件,并为您提供接近最佳的性能。

【讨论】:

  • statfs 的细节是平台特定的。也许 OP 的目标是 MS Windows,而不是一些 POSIX-ish 环境。
  • @TadeuszA.Kadłubowski:问题仅标记为c,但使用fgetc 和feof,所以我假设他使用的是POSIX 系统。但即使在 Windows 上,这个概念也适用:您不想进行大量的小读取(非常非常慢,因为开销非常大),而是希望尽可能少地进行最佳大小的读取。我很确定有一种 Windows 方法可以查询首选 I/O 大小。
  • 也许提到,采用 2**20 字节的缓冲区几乎可以保证是块大小的倍数。也许取其中两个,一个用于异步读取,另一个用于现在处理。
  • @Deduplicator:重点不是猜测,而是询问内核。例如,我在 iPad 上看到 4MB 块大小,所以你的 1MB 缓冲区已经太小了。
  • @TadeuszA.Kadłubowski 我只想在 POSIX 环境中使用它
【解决方案2】:

“有没有更好的方法?”

使用!feof(fp) 作为终止条件不是一个好主意。 你更适合

while ((ch = fgetc(fp)) != EOF)

并检查循环内的换行符(如上所述,考虑到所有可能的换行符)。

更多: http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1046476070&id=1043284351

【讨论】:

【解决方案3】:

我建议您尝试使用内存映射 IO 来让操作系统优化磁盘 IO(可能是您最大的瓶颈),而您只需计算行数。还要考虑一行可能由 4 种可能性中的任何一种表示:\r、\n、\r\n、文件结尾。

【讨论】:

    【解决方案4】:

    除非文件不包含任何带有元数据(如行号)的标题,否则查找此数字具有线性复杂性。 还要记住“\n”不是通用换行符。

    【讨论】:

    • 但这些文件格式是已知的,并由我们的一个应用程序创建。所以我知道 ""\n"" 是那里的换行符。
    • 很明显,复杂度对于任何算法(对于这个问题)都是线性的。但是性能的细节远远超出了所使用算法的复杂性。你还没有真正回答这个问题。
    • 取决于文件的打开方式:文本或二进制模式。
    猜你喜欢
    • 1970-01-01
    • 2013-11-27
    • 2013-02-13
    • 1970-01-01
    • 2013-12-31
    • 1970-01-01
    • 2016-02-09
    • 1970-01-01
    相关资源
    最近更新 更多