温馨提示×

如何用readdir实现目录备份

小樊
33
2025-11-15 17:14:48
栏目: 编程语言

使用 readdir 函数来实现目录备份,通常涉及遍历源目录中的所有文件和子目录,并将它们复制到目标位置。以下是一个使用 C 语言编写的示例程序,演示如何使用 readdir 实现目录备份:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>

// 函数声明
int copy_file(const char *src, const char *dest);
int copy_directory(const char *src, const char *dest);

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "用法: %s <源目录> <目标目录>\n", argv[0]);
        return EXIT_FAILURE;
    }

    const char *source = argv[1];
    const char *destination = argv[2];

    // 检查源目录是否存在
    struct stat st;
    if (stat(source, &st) != 0) {
        perror("无法获取源目录信息");
        return EXIT_FAILURE;
    }

    if (!S_ISDIR(st.st_mode)) {
        fprintf(stderr, "源路径不是一个目录: %s\n", source);
        return EXIT_FAILURE;
    }

    // 创建目标目录(如果不存在)
    if (mkdir(destination, st.st_mode) != 0 && errno != EEXIST) {
        perror("无法创建目标目录");
        return EXIT_FAILURE;
    }

    // 复制目录内容
    if (copy_directory(source, destination) != 0) {
        fprintf(stderr, "目录备份失败\n");
        return EXIT_FAILURE;
    }

    printf("目录备份成功: %s 到 %s\n", source, destination);
    return EXIT_SUCCESS;
}

// 复制单个文件
int copy_file(const char *src, const char *dest) {
    FILE *sf = fopen(src, "rb");
    if (!sf) {
        perror("无法打开源文件");
        return EXIT_FAILURE;
    }

    FILE *df = fopen(dest, "wb");
    if (!df) {
        perror("无法打开目标文件");
        fclose(sf);
        return EXIT_FAILURE;
    }

    size_t bytes_read;
    char buffer[4096];
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), sf)) > 0) {
        if (fwrite(buffer, 1, bytes_read, df) != bytes_read) {
            perror("写入目标文件时出错");
            fclose(sf);
            fclose(df);
            return EXIT_FAILURE;
        }
    }

    fclose(sf);
    fclose(df);
    return EXIT_SUCCESS;
}

// 递归复制目录
int copy_directory(const char *src, const char *dest) {
    DIR *dir = opendir(src);
    if (!dir) {
        perror("无法打开目录");
        return EXIT_FAILURE;
    }

    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
            continue; // 跳过当前目录和父目录

        char src_path[PATH_MAX];
        char dest_path[PATH_MAX];

        snprintf(src_path, sizeof(src_path), "%s/%s", src, entry->d_name);
        snprintf(dest_path, sizeof(dest_path), "%s/%s", dest, entry->d_name);

        struct stat st;
        if (stat(src_path, &st) != 0) {
            perror("无法获取文件/目录信息");
            closedir(dir);
            return EXIT_FAILURE;
        }

        if (S_ISDIR(st.st_mode)) {
            // 如果是目录,递归复制
            if (mkdir(dest_path, st.st_mode) != 0 && errno != EEXIST) {
                perror("无法创建目标子目录");
                closedir(dir);
                return EXIT_FAILURE;
            }
            if (copy_directory(src_path, dest_path) != 0) {
                closedir(dir);
                return EXIT_FAILURE;
            }
        } else {
            // 如果是文件,直接复制
            if (copy_file(src_path, dest_path) != 0) {
                closedir(dir);
                return EXIT_FAILURE;
            }
        }
    }

    closedir(dir);
    return EXIT_SUCCESS;
}

程序说明

  1. 参数检查

    • 程序接受两个命令行参数:源目录和目标目录。
    • 使用 stat 函数检查源路径是否为目录。
  2. 创建目标目录

    • 使用 mkdir 创建目标目录,如果已存在则忽略错误(EEXIST)。
  3. 复制目录内容

    • 使用 opendirreaddir 遍历源目录中的所有条目。
    • 对于每个条目,判断是文件还是子目录:
      • 文件:调用 copy_file 函数进行复制。
      • 子目录:递归调用 copy_directory 进行复制。
  4. 复制文件

    • 使用标准 I/O 函数 fopenfreadfwritefclose 逐块读取并写入文件内容。
  5. 错误处理

    • 在每一步操作后检查返回值,并在出错时输出相应的错误信息。

编译与运行

保存上述代码到一个文件,例如 backup.c,然后使用以下命令编译:

gcc -o backup backup.c

运行程序时提供源目录和目标目录作为参数:

./backup /path/to/source /path/to/destination

注意事项

  • 权限:确保程序有足够的权限读取源目录和写入目标目录。
  • 符号链接:上述程序不会处理符号链接。如果需要处理符号链接,可以在 copy_directory 中添加相应的逻辑。
  • 大文件:对于非常大的文件,可能需要调整缓冲区大小或优化复制方法以提高效率。
  • 跨平台:该示例适用于类 Unix 系统。如果在 Windows 上编译,需要包含相应的头文件并调整部分系统调用。

通过以上步骤,你可以使用 readdir 函数实现基本的目录备份功能。根据具体需求,你还可以扩展该程序以支持更多功能,如增量备份、日志记录、并行复制等。

0