You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

用C语言修改文本文件指定行时内容覆盖问题的解决建议

解决直接修改文件时后续行内容被覆盖的问题

问题根源

直接在原文件上原地修改内容时,若修改后的行长度与原行不一致,会导致文件指针位置偏移,后续字节被错误覆盖。比如原行file:=good\n(假设含换行符共10字节),替换为file:=newfile\n(共12字节)后,多出来的2个字节会覆盖下一行的前两个字符sr,最终导致src:=$(file).c变成:=$(file).c。

修正方案(不创建临时文件)

直接原地修改难以处理行长度变化的情况,可靠的做法是先将整个文件内容读取到内存,在内存中完成修改后再写回原文件。以下是具体实现代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // 用于ftruncate

#define BUFFER_SIZE 1024

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <new_file_name>\n", argv[0]);
        return 1;
    }

    const char *filename = "dummyFile.txt";
    FILE *fp = fopen(filename, "r+");
    if (!fp) {
        perror("Failed to open file");
        return 1;
    }

    // 1. 读取整个文件到内存
    char *content = NULL;
    size_t total_size = 0;
    char buffer[BUFFER_SIZE];
    size_t bytes_read;

    while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, fp)) > 0) {
        char *temp = realloc(content, total_size + bytes_read + 1);
        if (!temp) {
            perror("Failed to allocate memory");
            free(content);
            fclose(fp);
            return 1;
        }
        content = temp;
        memcpy(content + total_size, buffer, bytes_read);
        total_size += bytes_read;
    }
    content[total_size] = '\0'; // 添加字符串结束符

    // 2. 定位并修改目标行
    const char *target_prefix = "file:=";
    char *line_start = strstr(content, target_prefix);
    if (!line_start) {
        fprintf(stderr, "Target line not found\n");
        free(content);
        fclose(fp);
        return 1;
    }

    // 找到行尾(换行符或文件末尾)
    char *line_end = strchr(line_start, '\n');
    if (!line_end) line_end = content + total_size;

    // 构造新行
    char new_line[BUFFER_SIZE];
    snprintf(new_line, sizeof(new_line), "%s%s\n", target_prefix, argv[1]);
    int len_diff = strlen(new_line) - (line_end - line_start);

    // 根据长度差调整内存内容
    if (len_diff > 0) {
        // 需要扩展内存,移动后续内容
        char *temp = realloc(content, total_size + len_diff + 1);
        if (!temp) {
            perror("Failed to reallocate memory");
            free(content);
            fclose(fp);
            return 1;
        }
        content = temp;
        // 重新定位行起始和结束位置(内存地址可能变化)
        line_start = strstr(content, target_prefix);
        line_end = strchr(line_start, '\n');
        if (!line_end) line_end = content + total_size;
        memmove(line_end + len_diff, line_end, content + total_size - line_end);
        total_size += len_diff;
    } else if (len_diff < 0) {
        // 缩小内容,移动后续内容覆盖多余部分
        memmove(line_end + len_diff, line_end, content + total_size - line_end);
        total_size += len_diff;
    }

    // 写入新行
    memcpy(line_start, new_line, strlen(new_line));
    content[total_size] = '\0';

    // 3. 将修改后的内容写回文件并截断
    fseek(fp, 0, SEEK_SET);
    fwrite(content, 1, total_size, fp);
    ftruncate(fileno(fp), total_size); // 截断多余的旧内容

    // 清理资源
    free(content);
    fclose(fp);

    return 0;
}

关键说明

  • 内存中处理内容可以彻底避免原地修改的长度偏移问题,所有修改都在内存缓冲区完成
  • 通过计算新行与原行的长度差,移动后续内容来适配长度变化,确保所有行的位置正确
  • 使用ftruncate截断文件,避免原文件长度大于新内容时末尾残留旧数据
  • 适用于普通大小的makefile文件,若处理超大文件,需考虑分块读取修改的方案

内容的提问来源于stack exchange,提问作者John Doe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 04:43:28