使用opendir/readdir复制目录文件遇open失败及路径构造问题求助
解决目录文件复制中的
open()失败问题与路径构造方法 看起来你遇到的核心问题有两个:一是传递给copie函数的源文件路径不完整导致open()失败,二是不知道如何正确构造目标目录的文件路径。让我一步步帮你解决:
1. 为什么open()会失败?
你在copieRepertoire里拿到的sd->d_name只是单纯的文件名(比如file.txt),而不是完整的文件路径。当你直接把这个文件名传给copie函数时,open(source, ...)会在当前程序运行的工作目录下去找这个文件,而不是你指定的rsource目录里,自然找不到,所以返回-1触发错误。
2. 如何构造完整的源/目标文件路径?
你需要把目录路径和文件名拼接成完整路径,比如rsource/filename和rdest/filename。推荐用snprintf来安全拼接字符串(避免手动拼接的缓冲区溢出问题),步骤如下:
- 定义足够大的字符数组(比如
PATH_MAX,这是系统定义的最大路径长度,在limits.h里) - 用
snprintf把目录和文件名拼接进去
3. 代码中其他需要修复的潜在问题
除了路径问题,copie函数里还有几个bug需要修正:
open目标文件时,O_EXCL|O_APPEND的组合不合理:O_EXCL会在文件已存在时导致open失败,而O_APPEND是追加模式,复制文件应该用覆盖模式(加上O_TRUNC)- 没有循环调用
read和write:如果文件大小超过4096字节,一次read读不完,会导致文件复制不完整 - 缺少对
open目标文件、read、write的错误检查,难以定位问题
修正后的完整代码
#include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <dirent.h> #include <limits.h> // 引入系统定义的PATH_MAX #include <string.h> // 引入strcmp函数 void copie (char* source, char* dest) { char buf[4096]; // 打开源文件并检查错误 int fs = open(source, O_RDONLY); if (fs == -1) { perror("Failed to open source file"); exit(EXIT_FAILURE); } // 打开目标文件:用O_TRUNC覆盖已存在文件,去掉O_EXCL允许覆盖,保留O_CREAT创建新文件 int fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd == -1) { perror("Failed to open destination file"); close(fs); exit(EXIT_FAILURE); } // 循环读取并写入,直到文件结束 ssize_t size; while ((size = read(fs, buf, sizeof(buf))) > 0) { if (write(fd, buf, size) != size) { perror("Write failed"); close(fs); close(fd); exit(EXIT_FAILURE); } } if (size == -1) { perror("Read failed"); close(fs); close(fd); exit(EXIT_FAILURE); } // 复制源文件的权限 struct stat statut; if (fstat(fs, &statut) == -1) { perror("fstat failed"); close(fs); close(fd); exit(EXIT_FAILURE); } if (fchmod(fd, statut.st_mode) == -1) { perror("fchmod failed"); close(fs); close(fd); exit(EXIT_FAILURE); } close(fd); close(fs); } void copieRepertoire (char* rsource, char* rdest) { DIR *rs = opendir(rsource); DIR *rd = opendir(rdest); if (rs == NULL || rd == NULL){ perror("opendir failed"); exit(EXIT_FAILURE); } struct dirent *sd; char source_path[PATH_MAX]; char dest_path[PATH_MAX]; while ((sd = readdir(rs)) != NULL) { // 跳过.和..目录,避免无限循环 if (strcmp(sd->d_name, ".") == 0 || strcmp(sd->d_name, "..") == 0) { continue; } if (sd->d_type == DT_REG) { // 构造完整的源文件路径 snprintf(source_path, sizeof(source_path), "%s/%s", rsource, sd->d_name); // 构造完整的目标文件路径 snprintf(dest_path, sizeof(dest_path), "%s/%s", rdest, sd->d_name); printf("Copying %s to %s\n", source_path, dest_path); copie(source_path, dest_path); } } closedir(rs); closedir(rd); } int main(int argc, char *argv[]) { // 测试单个文件复制 copie("tes.txt","tese.txt"); // 测试目录复制 copieRepertoire ("rsource","rdest"); return 0; }
关键修改说明
- 路径拼接:用
snprintf构造source_path和dest_path,确保程序能找到正确的文件位置 - 跳过
.和..:避免复制当前目录和上级目录导致的无限循环 - 循环读写:保证大文件也能完整复制
- 完善错误处理:用
perror打印具体错误信息,方便调试 - 修正
open参数:用O_TRUNC替代O_APPEND,去掉O_EXCL允许覆盖已存在的目标文件
内容的提问来源于stack exchange,提问作者Lydia Zenaidi
相关产品推荐
相关产品推荐

