在Linux系统中,cp
命令用于复制文件或目录,本文将详细讲解如何用C语言实现基础的文件复制功能(仅限单个文件),涵盖核心系统调用、错误处理及代码实现。
实现原理
Linux的cp
命令本质是完成以下操作:
- 打开源文件(source)
- 创建目标文件(destination)
- 从源文件读取数据
- 将数据写入目标文件
- 处理错误并关闭文件
涉及关键系统调用:
open()
:打开/创建文件read()
:读取文件内容write()
:写入数据close()
:关闭文件描述符
完整代码实现
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define BUFFER_SIZE 4096 // 高效读写缓冲区大小
int main(int argc, char *argv[]) {
// 参数校验
if (argc != 3) {
fprintf(stderr, "Usage: %s <source> <destination>\n", argv[0]);
exit(EXIT_FAILURE);
}
int src_fd, dst_fd;
ssize_t bytes_read;
char buffer[BUFFER_SIZE];
// 1. 打开源文件 (只读模式)
src_fd = open(argv[1], O_RDONLY);
if (src_fd == -1) {
perror("Error opening source file");
exit(EXIT_FAILURE);
}
// 2. 创建目标文件 (读写模式 | 创建新文件 | 截断已存在文件)
dst_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (dst_fd == -1) {
perror("Error creating destination file");
close(src_fd); // 关闭已打开的源文件
exit(EXIT_FAILURE);
}
// 3. 循环读写数据
while ((bytes_read = read(src_fd, buffer, BUFFER_SIZE)) > 0) {
ssize_t bytes_written = write(dst_fd, buffer, bytes_read);
if (bytes_written != bytes_read) {
perror("Write error");
close(src_fd);
close(dst_fd);
exit(EXIT_FAILURE);
}
}
// 4. 检查读取错误
if (bytes_read == -1) {
perror("Read error");
close(src_fd);
close(dst_fd);
exit(EXIT_FAILURE);
}
// 5. 关闭文件描述符
if (close(src_fd) == -1) perror("Close source error");
if (close(dst_fd) == -1) perror("Close destination error");
printf("File copied successfully!\n");
return EXIT_SUCCESS;
}
关键代码解析
-
参数验证
argc != 3
确保用户输入源文件和目标文件路径。 -
文件打开模式
- 源文件:
O_RDONLY
(只读) - 目标文件:
O_WRONLY
(只写)
O_CREAT
(不存在则创建)
O_TRUNC
(存在则清空)
0644
(文件权限:用户读写,组和其他只读)
- 源文件:
-
高效读写循环
BUFFER_SIZE=4096
匹配磁盘块大小,减少系统调用次数read()
返回实际读取字节数,write()
确保写入等量数据
-
错误处理
- 所有系统调用后检查返回值
perror()
输出具体错误原因- 失败时关闭已打开的文件描述符
功能局限性说明
当前实现为基础版本,与系统cp
命令相比:
- ❌ 不支持目录复制
需使用opendir()
/readdir()
递归处理 - ❌ 不保留元数据
如权限、时间戳需额外调用fchmod()
/futimens()
- ❌ 无符号链接处理
需使用lstat()
判断文件类型 - ❌ 无大文件支持
超过2GB文件需定义_FILE_OFFSET_BITS=64
扩展建议
-
添加目录支持
#include <dirent.h> #include <sys/stat.h>
递归遍历目录,对每个文件调用复制函数。
-
保留文件属性
struct stat src_stat; fstat(src_fd, &src_stat); // 获取元数据 fchmod(dst_fd, src_stat.st_mode); // 复制权限
-
进度显示
通过lseek()
获取文件大小,计算并打印复制进度百分比。
编译与测试
- 编译代码:
gcc my_cp.c -o my_cp
- 测试复制:
./my_cp source.txt destination.txt
- 验证结果:
diff source.txt destination.txt # 无输出表示内容一致
本文实现的C语言版cp
命令覆盖了文件复制的核心逻辑,通过系统级I/O操作实现高效数据传输,实际开发中可逐步添加目录处理、权限保留等进阶功能,完整代码已通过GCC编译测试,适用于Linux环境下的基础文件操作场景。
引用说明:
本文代码基于Linux POSIX标准系统调用实现,参考《Advanced Programming in the UNIX Environment》(Richard Stevens著)中文件I/O操作规范,错误处理遵循IEEE Std 1003.1-2017标准。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/7566.html