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

如何使用系统调用write()不删除文件数据并实现内容插入?

解决方案:用write()在文件中间插入内容而不覆盖原有数据

这是个很典型的系统调用使用误区——write()本身并不支持「插入」操作,它只会从当前文件偏移量开始覆盖写入。你看到的Hello bad w就是因为新内容把原文件中从插入点开始的字符直接覆盖了。要实现真正的插入,得手动把插入点后面的内容先挪走,具体步骤和代码如下:

核心思路

底层文件系统没有「插入」的原生操作,所以我们需要手动完成这几个步骤:

  1. 以可读可写模式打开目标文件
  2. 定位到要插入的位置
  3. 读取插入点之后的所有内容并暂存
  4. 回退到插入位置,写入新内容
  5. 把暂存的原有内容追加到新内容之后

完整代码示例

#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main() {
    const char *filename = "test.txt";
    off_t insert_pos = 6; // 对应"Hello "之后的位置(共6个字符)
    const char *insert_str = "bad "; // 末尾加空格让最终结果为"Hello bad World"

    // 1. 打开文件:可读可写模式
    int fd = open(filename, O_RDWR);
    if (fd == -1) {
        perror("open failed");
        return EXIT_FAILURE;
    }

    // 2. 获取文件总大小,计算插入点后的剩余内容长度
    off_t file_size = lseek(fd, 0, SEEK_END);
    if (file_size == -1) {
        perror("lseek get file size failed");
        close(fd);
        return EXIT_FAILURE;
    }
    off_t remaining_len = file_size - insert_pos;

    // 3. 分配缓冲区,读取插入点后的所有内容
    char *buf = malloc(remaining_len + 1); // +1 是为了给字符串结束符留位置(可选,方便调试)
    if (!buf) {
        perror("malloc failed");
        close(fd);
        return EXIT_FAILURE;
    }

    // 回退到插入位置,读取剩余内容
    if (lseek(fd, insert_pos, SEEK_SET) == -1) {
        perror("lseek to insert pos failed");
        free(buf);
        close(fd);
        return EXIT_FAILURE;
    }
    ssize_t read_bytes = read(fd, buf, remaining_len);
    if (read_bytes != remaining_len) {
        perror("read failed or incomplete");
        free(buf);
        close(fd);
        return EXIT_FAILURE;
    }
    buf[read_bytes] = '\0'; // 可选,方便打印调试内容

    // 4. 再次回退到插入位置,写入新内容
    if (lseek(fd, insert_pos, SEEK_SET) == -1) {
        perror("lseek to insert pos failed again");
        free(buf);
        close(fd);
        return EXIT_FAILURE;
    }
    ssize_t write_bytes = write(fd, insert_str, sizeof("bad ") - 1); // 减去字符串自带的'\0'
    if (write_bytes != sizeof("bad ") - 1) {
        perror("write insert string failed");
        free(buf);
        close(fd);
        return EXIT_FAILURE;
    }

    // 5. 写入之前暂存的原有内容
    write_bytes = write(fd, buf, remaining_len);
    if (write_bytes != remaining_len) {
        perror("write remaining content failed");
        free(buf);
        close(fd);
        return EXIT_FAILURE;
    }

    // 清理资源
    free(buf);
    close(fd);

    printf("插入完成!\n");
    return EXIT_SUCCESS;
}

关键细节说明

  • 文件打开模式:必须用O_RDWR,这样才能同时完成读和写操作;如果是新文件可以加O_CREAT,但你的场景是操作已有文件,无需额外添加。
  • lseek()的使用:用来移动文件偏移量,SEEK_SET表示从文件开头计算位置,SEEK_END表示跳到文件末尾获取总大小。
  • 缓冲区分配:如果文件很大,一次性读取所有剩余内容可能占用过多内存,这时候可以分块读取/写入,避免内存溢出。
  • 错误处理:每个系统调用(open/lseek/read/write/malloc)都要检查返回值,避免出现隐性错误。
  • 多进程/线程场景:如果有多个进程同时操作该文件,需要加文件锁(比如flock()或fcntl()的记录锁)来避免竞态条件。

内容的提问来源于stack exchange,提问作者Nelson Sousa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 11:11:37