C语言对比两个txt文件时首次循环后文件未从开头读取问题
问题根因
C语言文件流采用顺序读写机制,打开文件后内部维护的位置指针会随着读取操作向后移动:第一次遍历current.txt完成后,指针已经停在文件末尾(EOF)位置,同时流上会标记EOF状态。后续再对current.txt调用读取接口时,会直接从EOF位置开始读,自然读不到任何有效内容,无法实现从头全量比对的预期。
修复方案
两种可落地的实现方式,优先选第一种:
- 方案1(推荐,性能更高):每完成一次
current.txt的全量遍历后,调用接口将文件位置指针重置到文件起始位置,同时清除EOF标记,不需要反复开关文件。 - 方案2(仅适合极小文件场景):每读取一条
backedup.txt的记录,就重新fopen打开一次current.txt做遍历,遍历完成后fclose关闭。这种方式每次打开文件指针默认在开头,但是频繁IO开销大,文件条目多的时候速度很慢。
可直接运行的修正代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_LINE_LEN 256 // 可根据文件名/路径最大长度调整数值 int main() { FILE *f_backup = fopen("backedup.txt", "r"); FILE *f_current = fopen("current.txt", "r"); // 校验文件打开状态 if (!f_backup || !f_current) { perror("文件打开失败"); exit(EXIT_FAILURE); } char backup_name[MAX_LINE_LEN]; char current_name[MAX_LINE_LEN]; // 外层逐行读取备份文件列表 while (fgets(backup_name, MAX_LINE_LEN, f_backup)) { // 清除fgets读入的行尾换行符 backup_name[strcspn(backup_name, "\r\n")] = 0; // 核心操作:每次比对前将current.txt的读指针重置到文件开头,同时清除EOF标记 rewind(f_current); // 内层逐行读取当前文件列表做比对 while (fgets(current_name, MAX_LINE_LEN, f_current)) { current_name[strcspn(current_name, "\r\n")] = 0; if (strcmp(backup_name, current_name) == 0) { printf("Found: %s\n", backup_name); break; // 匹配成功即可跳出内层循环,无需继续遍历剩余条目 } } } fclose(f_backup); fclose(f_current); return 0; }
关键注意事项
- 重置文件指针优先用
rewind(文件指针),这个接口会同时完成「指针移到文件开头」+「清除流上的EOF/错误标记」两个操作,比单独调用fseek更适配这个场景;如果用fseek(f_current, 0, SEEK_SET),需要额外调用clearerr(f_current)清除EOF标记,否则后续读取可能异常。 - 不要用
fscanf("%s", 缓冲区)逐行读文件名:%s格式符遇到空格、制表符就会停止读取,如果mp3文件名包含空格会被截断,直接导致比对失败。推荐用fgets读整行,之后手动去掉行尾的\r、\n换行符再做字符串比对。 - 如果两个列表的条目数量很大(比如上千条),反复从头遍历
current.txt的时间复杂度是O(n*m),性能很差,可以提前把current.txt的所有文件名读到内存的数组或者哈希表中,后续比对直接在内存中完成,性能会提升几个数量级。
内容的提问来源于stack exchange,提问作者user19364460
相关产品推荐
相关产品推荐

