You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

两种文本文件行数统计代码,哪种更优且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

火山引擎 最新活动