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
相关产品推荐
相关产品推荐

