计算文件中行号的最简单方法是:
while(!feof(fp))
{
ch = fgetc(fp);
if(ch == '\n')
{
lines++;
}
}
但现在的要求是我必须计算大文件中的行数。它会对性能产生影响。
有更好的方法吗?
答案 0 :(得分:6)
对于速度最快的I / O,您通常希望以文件系统/操作系统的块大小的倍数读/写。
您可以通过调用文件或文件描述符上的statfs
或fstatfs
来查询块大小(阅读手册页)。
struct statfs
有一个字段f_bsize
,有时也有f_iosize
:
最佳传输块大小
所有POSIX系统AFAIK上都存在f_bsize
字段。在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"虽然我上面描述的方法始终适用于任意大小的文件,并为您提供接近最佳的性能。
答案 1 :(得分:3)
“有更好的方法吗?”
使用!feof(fp)
作为终止条件并不是一个好主意。
while ((ch = fgetc(fp)) != EOF)
检查循环内的新行(如上所述,考虑所有可能的换行符)。
更多信息: http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1046476070&id=1043284351
答案 2 :(得分:1)
我建议尝试内存映射IO以允许操作系统优化磁盘IO(可能是您最大的瓶颈),而您只需计算行数。还可以考虑一条线可以用4种可能中的任何一种来表示:\ r,\ n,\ r \ n,end-of-file。
答案 3 :(得分:0)
除非文件不包含任何包含行号等元数据的标题,否则查找此数字具有线性复杂性。 还要记住" \ n"不是普遍的换行符。