C语言反向操作文件定位并修改指定年龄人员信息的问题求助
提问内容
我有一个存储了姓名、姓氏和年龄的文件,内容如下:
john doe 20
lionel messi 33
cristiano ronaldo 35
我想要实现的功能是根据年龄查询到指定人员,再修改其任意信息。下方示例代码中,我尝试查找年龄为35的人员并修改其年龄值:
#include <stdio.h> #include <string.h> int main () { char line[30]; FILE *fp; int age; if (!(fp = fopen("test.txt", "rb"))) { /* 校验文件是否成功打开用于读取 */ perror ("file open failed"); return; } char name[20], surname[20]; while (fgets (line, 30, fp)) { int off = 0; while (sscanf (line, "%s%s%d%n", name, surname, &age, &off) == 3) { if(age == 35) { fseek(fp,-2, SEEK_CUR); printf("%s", name); fprintf(fp, "%d", 19); } strcpy(line, line+off); } } fclose(fp); return 0; }
但代码运行不符合预期,有时能成功更新信息有时不行。
解答
问题根因
- 文件打开模式错误:你使用的
rb是只读模式,没有写入权限,fprintf写入操作会直接失效,这是核心问题。 - 读写交替未做状态切换:C语言标准明确规定,同一文件流上交替执行读、写操作时,两次操作中间必须调用
fflush()或者文件定位类函数(fseek/fsetpos/rewind)切换流状态,否则行为完全未定义,这就是代码时好时坏的直接原因。 - 回退字节数逻辑硬编码不兼容:固定回退2个字节的写法只适用于年龄刚好是2位、换行符长度符合预期的场景,一旦年龄是1位/3位、或者不同系统换行符长度不同(Windows是2字节,Linux是1字节),定位就会直接错位。
- 直接修改原文件风险高:如果修改后的内容长度和原内容不一致,会直接覆盖相邻行的内容,导致文件损坏。
正确实现方案
推荐用「读原文件+写临时文件+替换原文件」的方案,逻辑简单容错率高,不会出现定位错误的问题:
#include <stdio.h> #include <string.h> #include <stdlib.h> int main () { char line[100]; FILE *fp, *tmp_fp; int age; char name[20], surname[20]; int target_age = 35, new_age = 19; // 打开原文件读 if (!(fp = fopen("test.txt", "r"))) { perror("原文件打开失败"); return 1; } // 打开临时文件写 if (!(tmp_fp = fopen("tmp_test.txt", "w"))) { perror("临时文件创建失败"); fclose(fp); return 1; } while (fgets(line, sizeof(line), fp)) { // 解析当前行内容 if (sscanf(line, "%s %s %d", name, surname, &age) == 3) { if (age == target_age) { // 匹配到目标行,写修改后的内容 fprintf(tmp_fp, "%s %s %d\n", name, surname, new_age); continue; } } // 没匹配到的行原样写入临时文件 fputs(line, tmp_fp); } fclose(fp); fclose(tmp_fp); // 替换原文件 remove("test.txt"); rename("tmp_test.txt", "test.txt"); return 0; }
如果你一定要直接在原文件上修改,需要把打开模式改成r+b(读写二进制模式),并且每次写入前确认定位的偏移量准确,读写操作之间加定位操作切换状态。
内容的提问来源于stack exchange,提问作者akoluacik
相关产品推荐
相关产品推荐

