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

C语言实现文件拷贝时目标文件为空的问题排查

文件复制程序异常:内容输出到控制台而非目标文件的问题解决

问题描述

编写了一个C程序,通过命令行参数指定源文件和目标文件,以512字节为块读取源文件内容并写入目标文件,但运行后目标文件为空,源文件内容反而输出到控制台。

尝试代码

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

int main(int argc, char* argv[]){
    if(argc < 2){
        printf("ERROR: Missing arguments\n");
        exit(1);    
    }

    int fdo, fdd;

    if((fdo = open(argv[1], O_RDONLY)) == -1){
        printf("ERROR: Origin file %s can not be opened\n", argv[1]);
        exit(1);
    }

    if(fdd = open(argv[2], O_CREAT | O_TRUNC, 0666) == -1){
        printf("ERROR: Dest. file %s can not be opened\n", argv[2]);
        exit(1);
    } 

    char buff[512];
    size_t n_bytes;

    while((n_bytes = read(fdo,buff,512)) > 0){
        if(write(fdd,buff,n_bytes) < 0){
            printf("Can not write buffer content in %s \n", argv[2]);
            exit(1);
        }
    }

    if(n_bytes < 0){
        printf("Can not read %s file \n", argv[1]);
        exit(1);
    }

    close(fdo);
    close(fdd);

    return 0;
}

测试环境与运行结果

测试文件test.txt内容:

abcdef
1890

文件权限:

usuarioso@usuarioso-virtualbox:~/Documentos/SO 2022/pr2/API de ficheros y directorios$ ls -l
total 32
-rwxrwxr-x 1 usuarioso usuarioso 17048 nov 23 16:15 copyrf
-rw-rw-r-- 1 usuarioso usuarioso   774 nov 23 16:39 copyrf.c
-rw-rw-r-- 1 usuarioso usuarioso    12 nov 23 16:52 test.txt

运行程序后的结果:

usuarioso@usuarioso-virtualbox:~/Documentos/SO 2022/pr2/API de ficheros y directorios$ gcc -o copyrf copyrf.c
usuarioso@usuarioso-virtualbox:~/Documentos/SO 2022/pr2/API de ficheros y directorios$ ./copyrf test.txt test1.txt
abcdef
1890
usuarioso@usuarioso-virtualbox:~/Documentos/SO 2022/pr2/API de ficheros y directorios$ ls -l
total 28
-rwxrwxr-x 1 usuarioso usuarioso 17008 nov 23 17:00 copyrf
-rw-rw-r-- 1 usuarioso usuarioso   771 nov 23 16:59 copyrf.c
-rw-rw-rw- 1 usuarioso usuarioso     0 nov 23 17:00 test1.txt
-rw-rw-r-- 1 usuarioso usuarioso    12 nov 23 16:52 test.txt
usuarioso@usuarioso-virtualbox:~/Documentos/SO 2022/pr2/API de ficheros y directorios$ cat test1.txt

错误原因

核心问题是运算符优先级错误:

  • ==运算符的优先级高于=,所以代码中if(fdd = open(argv[2], O_CREAT | O_TRUNC, 0666) == -1)的执行顺序是:先计算open(...) == -1,将结果(布尔值0或1)赋值给fdd。
  • 因为目标文件成功创建时,open返回大于0的文件描述符,所以open(...) == -1的结果是false(即0),最终fdd被赋值为0。
  • 而0是标准输出(stdout)的文件描述符,后续的write(fdd, buff, n_bytes)实际上是把内容输出到了控制台,而非目标文件。
  • 同时,赋值后的fdd为0,if(0)不会触发错误提示,导致问题被隐藏。

另外,打开目标文件时缺少O_WRONLY标志,虽然O_CREAT结合O_TRUNC也能允许写入,但明确指定O_WRONLY更符合写入操作的语义,避免歧义。

修正后的代码

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

int main(int argc, char* argv[]){
    if(argc < 3){
        printf("ERROR: Missing arguments\nUsage: %s <source-file> <dest-file>\n", argv[0]);
        exit(1);    
    }

    int fdo, fdd;

    if((fdo = open(argv[1], O_RDONLY)) == -1){
        perror("ERROR opening origin file");
        exit(1);
    }

    if( (fdd = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, 0666)) == -1 ){
        perror("ERROR opening destination file");
        exit(1);
    } 

    char buff[512];
    ssize_t n_bytes;

    while( (n_bytes = read(fdo, buff, sizeof(buff))) > 0 ){
        if( write(fdd, buff, n_bytes) != n_bytes ){
            perror("ERROR writing to destination file");
            exit(1);
        }
    }

    if(n_bytes < 0){
        perror("ERROR reading source file");
        exit(1);
    }

    close(fdo);
    close(fdd);

    return 0;
}

额外优化说明

  • 参数检查修正:原代码argc < 2错误,因为需要源文件和目标文件两个参数,所以应该检查argc < 3,同时添加使用提示。
  • 使用perror替代自定义printf:perror会自动结合系统错误码输出详细错误信息,更便于调试。
  • 变量类型修正:read返回的是ssize_t(带符号整数),而非size_t,避免处理负返回值时的类型转换问题。
  • 写入检查优化:不仅检查写入是否失败(返回<0),还要检查写入的字节数是否与读取的一致,避免部分写入的情况。

验证

修正后重新编译运行,目标文件test1.txt会正确复制test.txt的内容,控制台不会输出源文件内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 15:20:24