如何使用POSIX系统调用实现多文件重复复制至指定目录
基于POSIX系统调用实现多文件复制工具
需求说明
- 实现命令行复制工具,仅使用POSIX标准系统调用完成操作
- 支持传入多个源文件路径(允许重复指定同一文件),最后一个参数固定为目标目录
- 将每个源文件复制到目标目录下,保持原文件名不变
测试环境准备
运行以下Shell脚本创建测试目录和文件:
setup () { mkdir -p t/a t/b echo "XXXX" > t/a/a echo "XXXX" > t/b/a echo "MMMM" > t/a/b } setup
实现思路
核心依赖POSIX标准系统调用完成文件操作,流程如下:
- 参数校验:确保命令行参数数量≥2,且最后一个参数为合法目录
- 遍历所有源文件(除最后一个参数外的所有参数):
- 用
stat检查源文件是否为常规文件 - 用
open以只读模式打开源文件 - 构造目标文件路径:目标目录 + 源文件的基础文件名(通过
basename获取) - 用
open以「只写+创建+截断」模式打开目标文件,继承源文件权限 - 循环调用
read读取源文件内容到缓冲区,再用write写入目标文件,直到读取完毕 - 关闭源文件和目标文件描述符
- 用
- 错误处理:对每个系统调用返回值做检查,出现错误时用
perror打印信息并继续处理下一个文件
完整代码实现
基于给定的起始代码补全如下:
#include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <unistd.h> #include <libgen.h> #include <string.h> #define BS 512 int main(int argc, char *argv[]) { // 校验参数数量 if (argc < 2) { fprintf(stderr, "用法: %s <源文件1> [源文件2...] <目标目录>\n", argv[0]); exit(EXIT_FAILURE); } // 处理目标目录:最后一个参数 char *dest_dir = argv[argc - 1]; struct stat dest_stat; if (stat(dest_dir, &dest_stat) == -1 || !S_ISDIR(dest_stat.st_mode)) { fprintf(stderr, "错误: %s 不是合法目录\n", dest_dir); exit(EXIT_FAILURE); } // 遍历所有源文件 for (int i = 1; i < argc - 1; i++) { char *src_path = argv[i]; struct stat src_stat; // 检查源文件是否为常规文件 if (stat(src_path, &src_stat) == -1) { perror(src_path); continue; } if (!S_ISREG(src_stat.st_mode)) { fprintf(stderr, "%s 不是常规文件,跳过\n", src_path); continue; } // 打开源文件 int src_fd = open(src_path, O_RDONLY); if (src_fd == -1) { perror(src_path); continue; } // 构造目标文件路径 char *src_basename = basename(src_path); char dest_path[1024]; snprintf(dest_path, sizeof(dest_path), "%s/%s", dest_dir, src_basename); // 打开目标文件 int dest_fd = open(dest_path, O_WRONLY | O_CREAT | O_TRUNC, src_stat.st_mode); if (dest_fd == -1) { perror(dest_path); close(src_fd); continue; } // 循环读写数据 ssize_t bytes_read; char buf[BS]; while ((bytes_read = read(src_fd, buf, BS)) > 0) { if (write(dest_fd, buf, bytes_read) != bytes_read) { perror(dest_path); close(src_fd); close(dest_fd); goto next_file; } } if (bytes_read == -1) { perror(src_path); } // 关闭文件描述符 close(src_fd); close(dest_fd); next_file: continue; } return EXIT_SUCCESS; }
编译与测试
- 编译代码:
gcc copy.c -o copy
- 运行示例命令:
# 示例1:重复复制t/a/a两次,复制t/a/b一次到t/b/ ./copy t/a/a t/a/a t/a/b t/b/ # 示例2:重复复制t/a/b三次,复制t/a/a一次到t/b/ ./copy t/a/a t/a/b t/a/b t/a/b t/b/
- 验证结果:
# 查看目标目录文件 ls t/b/ # 检查文件内容 cat t/b/a t/b/b
内容的提问来源于stack exchange,提问作者CopX
相关产品推荐
相关产品推荐

