两种文本文件行数统计代码,哪种更优且bug更少?
嘿,咱们来好好聊聊这两种统计文件行数的方案,从性能、适用场景到潜在坑点都拆解清楚~
两种文件行数统计方案的对比分析
先把两个完整的可运行代码补全(原代码漏了文件关闭操作,实际开发里可不能忘),方便咱们对照:
代码片段1(按行批量读取)
#include <stdio.h> #include <stdlib.h> #define BUFSIZ 1024 void count_lines_v1(const char *filename) { FILE *infile; int count = 0; char filearray[BUFSIZ]; infile = fopen(filename, "r"); if(infile == NULL) { perror("Could not open file"); exit(EXIT_FAILURE); } while(fgets(filearray, BUFSIZ, infile) != NULL) { count++; } fclose(infile); printf("Line count: %d\n", count); }
代码片段2(逐字符读取判断换行)
#include <stdio.h> #include <stdlib.h> void count_lines_v2(const char *filename) { FILE *infile; int c, count = 0; infile = fopen(filename, "r"); if(infile == NULL) { perror("Could not open file"); exit(EXIT_FAILURE); } while((c = fgetc(infile)) != EOF) { if(c == '\n') count++; } fclose(infile); printf("Line count: %d\n", count); }
接下来从几个核心维度对比两者的优劣:
1. 性能差异
- 方案1(
fgets):因为是按缓冲区批量读取,能大幅减少用户态和内核态的切换次数,大文件场景下性能明显更优。标准库的fgets会依托底层的文件IO缓存(默认通常是4KB或更大),实际磁盘IO的次数远少于逐字符读取的方式。 - 方案2(
fgetc):每次只读取一个字符,哪怕标准库有stdio层缓存,还是会有更多的函数调用开销,大文件下效率会略低。但小文件的话,这点差异几乎感知不到。
2. 内存占用
- 方案1:需要分配一块固定大小的缓冲区(这里是1024字节),内存占用略高,但这个量级的消耗在现代系统里完全可以忽略。
- 方案2:只需要一个
int变量存字符,内存占用极小,对于内存极度受限的嵌入式场景会更友好。
3. 边界情况的坑点
这是最容易踩雷的地方:
- 文件末尾无换行符:两种方案都会漏统计最后一行(如果最后一行没以
\n结尾)。比如文件内容是hello world(无换行),两者的计数都会是0。要解决的话,方案1需要检查最后一次读取的内容是否非空且不以\n结尾;方案2要在循环结束后判断最后一个字符不是\n且文件不为空。 - 超长行问题:如果文件里有一行长度超过缓冲区大小(比如1024字节),
fgets会截断这一行,分多次读取,此时方案1会把这一行统计成多行,直接导致计数错误!而方案2逐字符判断换行符,完全不受超长行影响——这是方案1的致命缺陷,要是你的场景可能出现超长行,绝对不能用方案1。
4. 代码可读性
- 方案1逻辑更直观:直接按行计数,刚接触C的人也能一眼看懂;方案2需要逐字符判断换行,逻辑稍微绕一点,但也不难理解。
总结建议
- 要是你的场景是普通文本文件、行长度不会超过缓冲区、且文件较大:优先选方案1,性能更好。
- 要是存在超长行,或者内存极度受限:必须选方案2,避免计数错误或内存不足。
- 小文件的话:两者差异不大,选哪个全看个人习惯。
内容的提问来源于stack exchange,提问作者user8753900




