修改配置文件值后残留多余字符的解决方法及程序优化咨询
问题原因
你遇到的残留问题本质是新写入的字符串长度短于原行长度:原行name3 = value3(含换行符)的长度比新行name3 = 89长,用fputs写入新内容后,原行未被覆盖的剩余字符就留在了文件里。
修复现有代码的方法
针对当前代码,有两种优雅的解决思路:
方法1:填充空白覆盖残留
计算原行与新行的长度差,写入对应数量的空格覆盖残留字符:
#include <stdio.h> #include <string.h> #define MAX_LEN 64 int main(void) { FILE *fp = fopen("a.txt", "r+"); char line[MAX_LEN]; long l = 89; size_t orig_len; while (fgets(line, MAX_LEN, fp)) { orig_len = strlen(line); if (strncmp(line, "name3", 5) == 0) { fseek(fp, -orig_len, SEEK_CUR); sprintf(line, "name3 = %ld\n", l); // 保留换行符维持行结构 size_t new_len = strlen(line); fputs(line, fp); // 用空格覆盖原行剩余字符 if (orig_len > new_len) { for (size_t i = 0; i < orig_len - new_len; i++) { fputc(' ', fp); } } goto close; } } close: fflush(fp); fclose(fp); }
方法2:截断文件
写入新内容后,直接截断文件到当前写入位置,丢弃后续残留字符:
#include <stdio.h> #include <string.h> #include <unistd.h> // POSIX系统头文件,Windows改用<io.h>和_chsize #define MAX_LEN 64 int main(void) { FILE *fp = fopen("a.txt", "r+"); char line[MAX_LEN]; long l = 89; while (fgets(line, MAX_LEN, fp)) { if (strncmp(line, "name3", 5) == 0) { fseek(fp, -strlen(line), SEEK_CUR); sprintf(line, "name3 = %ld\n", l); fputs(line, fp); // 获取当前位置并截断文件 long pos = ftell(fp); ftruncate(fileno(fp), pos); // Windows替换为_chsize(fileno(fp), pos) goto close; } } close: fflush(fp); fclose(fp); }
更优的程序写法
直接修改原文件的方式容易出现残留、中途崩溃损坏文件等问题,更可靠的是采用**「读入内存→修改→重写文件」**的模式:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_LINE_LEN 64 #define BUF_SIZE 1024 // 根据文件实际大小调整 int main(void) { FILE *src_fp = fopen("a.txt", "r"); if (!src_fp) { perror("打开源文件失败"); return 1; } // 读取全部内容到缓冲区 char buf[BUF_SIZE] = {0}; fread(buf, 1, BUF_SIZE - 1, src_fp); fclose(src_fp); // 逐行处理并修改目标内容 char *line = strtok(buf, "\n"); char *output = malloc(BUF_SIZE); if (!output) { perror("内存分配失败"); return 1; } output[0] = '\0'; while (line != NULL) { if (strncmp(line, "name3", 5) == 0) { strcat(output, "name3 = 89\n"); } else { strcat(output, line); strcat(output, "\n"); } line = strtok(NULL, "\n"); } // 写入回原文件 FILE *dst_fp = fopen("a.txt", "w"); if (!dst_fp) { perror("打开目标文件失败"); free(output); return 1; } fputs(output, dst_fp); fclose(dst_fp); free(output); return 0; }
这种模式的优势:
- 避免直接修改原文件的风险,中途崩溃不会损坏原始数据
- 逻辑清晰,彻底杜绝字符残留问题
- 适合绝大多数小型配置文件的修改场景
如果文件过大不适合一次性读入内存,可以改用「逐行写入临时文件→修改完成后替换原文件」的方式,核心逻辑一致。
内容的提问来源于stack exchange,提问作者babon
相关产品推荐
相关产品推荐

