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

C语言使用管道复制文件时缓冲区残留字符问题求助

解决管道文件复制时缓冲区残留字符的问题

嘿,我来帮你搞定这个问题!你遇到的末尾残留字符的问题,核心原因很明确:你每次都固定写入10字节,但最后一次读取到的字节数其实小于10,这时候缓冲区里之前留下的旧数据就被一起写到目标文件里了,所以才会多出那个“p”,导致MD5校验不一致。

关键修复思路

解决这个问题的核心就是不要固定读写10字节,而是根据每次read的实际返回值来决定写入的字节数:

  • 每次调用read后,保存它的返回值(这个值就是实际读取到的字节数,返回0表示文件读取完毕,返回-1表示出错)
  • 写入的时候,用这个实际读取的字节数作为写入长度,而不是硬写10字节

修改后的完整代码

我把你的代码做了针对性修改,标注了关键改动点:

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

int main(int argc, char *argv[]) {
    int fd[2];
    char message[10]; // 10字节缓冲区
    int filefd;

    // 创建管道(补上你代码中可能遗漏的管道初始化)
    if (pipe(fd) == -1) {
        perror("pipe failed");
        exit(EXIT_FAILURE);
    }

    // ====== 写者部分(读取in.txt,写入管道)======
    filefd = open(argv[1], O_RDONLY, 0);
    if (filefd == -1) {
        perror("open input file failed");
        exit(EXIT_FAILURE);
    }

    ssize_t bytes_read; // 用ssize_t存储read返回值,支持负数错误码
    int i = 0;
    // 循环读取文件,直到read返回0(结束)或-1(错误)
    while ((bytes_read = read(filefd, message, 10)) > 0) {
        // 用%.*s指定打印长度,避免输出缓冲区垃圾字符
        printf("writer: msg%d=%.*s\n", i+1, (int)bytes_read, message);
        fflush(stdout);
        // 关键:写入实际读取的字节数,而非固定10
        write(fd[1], message, bytes_read);
        usleep(100000);
        i++;
    }
    // 检查read是否出错
    if (bytes_read == -1) {
        perror("read input file failed");
        exit(EXIT_FAILURE);
    }
    close(filefd);
    close(fd[1]); // 写完管道后关闭写端,让读端知道数据已结束

    // ====== 读者部分(读取管道,写入out.txt)======
    filefd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (filefd == -1) {
        perror("open output file failed");
        exit(EXIT_FAILURE);
    }

    i = 0;
    while ((bytes_read = read(fd[0], message, 10)) > 0) {
        printf("reader: msg%d=%.*s\n", i+1, (int)bytes_read, message);
        fflush(stdout);
        // 同样:写入实际读取的字节数
        write(filefd, message, bytes_read);
        usleep(120000);
        i++;
    }
    if (bytes_read == -1) {
        perror("read pipe failed");
        exit(EXIT_FAILURE);
    }
    close(filefd);
    close(fd[0]);

    return 0;
}

额外说明

  1. 关于ssize_t:这个类型专门用来存储系统调用的返回值,它可以表示负数(错误)、0(结束)和正整数(实际字节数),比int更适配这类场景。
  2. 关于%.*s:这个格式符的作用是按指定长度打印字符串,避免打印缓冲区里未被覆盖的垃圾字符(比如之前残留的“p”),让调试输出更准确。
  3. 关闭管道端点:写完管道后一定要关闭写端,这样读端的read才会在数据读完后返回0,否则读端会一直阻塞等待数据。

修改后再运行程序,目标文件out.txt的内容就会和in.txt完全一致,MD5校验结果也会相同啦!

内容的提问来源于stack exchange,提问作者Szymon 呕ak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:47:10