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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:35:05