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

FILE流缓冲区工作原理及文件复制中缓冲区直接传输的疑问

为什么不能直接在源文件与目标文件的缓冲区之间直接传输数据?

好问题!你已经准确理解了fopen会为文件创建内部读写缓冲区,那为什么示例里的_copy函数非要用临时数组作为fread和fwrite的中转,而不能直接把源文件的内部缓冲区数据“搬运”到目标文件的内部缓冲区呢?这里有几个核心原因:

  • 标准库的封装性限制:C标准库中FILE结构体的内部缓冲区属于私有实现细节,C标准并没有规定开发者可以直接访问或操作这些缓冲区。不同编译器(比如GCC、MSVC)甚至同一编译器的不同版本,对FILE的内部结构定义都可能不同。如果硬要去读写这些内部缓冲区,你的代码会彻底失去可移植性,而且很容易因为库的更新而崩溃。fread和fwrite的设计就是通过用户提供的缓冲区来隔离这些内部细节,保证代码的兼容性。

  • 数据传输的可控性与灵活性:使用临时数组中转,你可以完全掌控每次传输的数据量(比如示例中定义的BUFF大小),还能在传输过程中轻松加入额外逻辑——比如修改数据内容、统计传输的字节数、过滤特定数据等。如果直接在内部缓冲区之间传输,你就完全失去了这种控制权,无法干预数据的流动过程。

  • 缓冲区的状态同步需求:每个文件的内部缓冲区都和文件的读写状态(比如当前文件偏移量、错误标记、EOF状态)紧密绑定。源文件的内部缓冲区可能还没被填满,或者目标文件的内部缓冲区还没准备好接收新数据,直接拷贝内部缓冲区会打破这些状态的同步机制。而fread和fwrite会自动处理这些状态:fread负责将磁盘数据读取到用户缓冲区(同时管理源文件的内部缓冲和偏移量),fwrite负责将用户缓冲区的数据写入目标文件的内部缓冲(并在缓冲区满时自动刷写到磁盘)。

  • 函数接口的设计逻辑:fread和fwrite的接口设计本身就围绕用户缓冲区展开。fread需要你提供一个用户空间的指针来存储读取的数据,fwrite需要你提供要写入数据的指针——这两个函数从设计上就没有支持直接在两个FILE流之间传输数据的能力,因为这种场景完全可以通过用户缓冲区中转实现,且灵活性更高。

补充一点:有些操作系统提供了底层系统调用(比如Linux的splice)可以直接在文件描述符之间传输数据,跳过用户空间的拷贝,但这属于系统级功能,C标准库并没有封装这类接口。你示例中的代码是标准C环境下最稳妥、可移植性最好的文件拷贝实现方式。


你提供的示例代码

/* 示例:copyfile.exe xxxxx.txt zzzzzz.txt */
#include <stdio.h>
#include <stdlib.h>
#define BUFF 8192
void _copy(FILE *source, FILE *destination);
int main(int argc, char *argv[]) {
    FILE *fp1, *fp2; // fp1 源文件指针// fp2 复制文件指针
    if (argc !=3 ) // 命令行必须包含3个参数
    {
        fprintf(stderr, "Usage: %s (source file) (copy file)\n", argv[0][0]);
        exit(EXIT_FAILURE);
    }
    if ((fp1 = fopen(argv[1], "rb")) == NULL) // 打开源文件
    {
        fprintf(stderr, "Could not open %s\n",argv[1]);
        exit(EXIT_FAILURE);
    }
    if((fp2 = fopen(argv[2], "ab+")) == NULL) // 打开目标文件
    {
        fprintf(stderr, "could not create %s \n",argv[2]);
        exit(EXIT_FAILURE);
    }
    if( setvbuf(fp1,NULL, _IOFBF, BUFF) != 0) // 设置源文件缓冲区
    {
        fputs("Can't create output buffer\n", stderr);
        exit(EXIT_FAILURE);
    }
    if( setvbuf(fp2,NULL, _IOFBF, BUFF) != 0) // 设置目标文件缓冲区
    {
        fputs("Can't create input buffer\n", stderr);
        exit(EXIT_FAILURE);
    }
    _copy(fp1, fp2);
    if (ferror(fp1)!=0)
        fprintf(stderr, "Error reading file %s\n", argv[1]);
    if(ferror(fp2)!=0)
        fprintf(stderr, "Error writing file %s\n",argv[2]);
    printf("Done coping %s (source) to %s (destination) \n",argv[1], argv[2]);
    fclose(fp1);
    fclose(fp2);
    return (0);
}
void _copy(FILE *source, FILE *destination)
{
    size_t bytes;
    static char temp[BUFF];
    while((bytes = fread(temp,sizeof(char),BUFF,source))>0)
        fwrite(temp,sizeof(char),bytes,destination);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:27:34