宏观理解
我们的目标是在Linux系统下编写文件拷贝程序。该程序的任务是复制文件,其流程可以拆解如下:
打开源文件
↓
打开目标文件
↓
循环读取源文件
↓
写入目标文件
↓
关闭两个文件
程序实现
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int src_fd; // 源文件描述符(source file descriptor)
int dst_fd; // 目标文件描述符
char buffer[1024];
int bytes_read;
// "./copy a.txt b.txt":argc = 3,argv[0] = "./copy",argv[1] = "a.txt",argv[2] = "b.txt"
if (argc != 3)
{
printf("Usage: %s source_file destination_file\n", argv[0]);
return 1;
}
// 1、打开源文件
src_fd = open(argv[1], O_RDONLY); // 只读的方式打开目标文件:a.txt
// 打开失败会返回:src_fd = -1
if (src_fd < 0)
{
printf("Cannot open source file\n");
return 1;
}
// 2、打开目标文件
// 只写 | 如果文件不存在就创建 | 如果文件已经存在则清空文件
dst_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (dst_fd < 0)
{
printf("Cannot open destination file\n");
return 1;
}
// 3、循环读取源文件
while ((bytes_read = read(src_fd, buffer, sizeof(buffer))) > 0)
{
// 4、写入目标文件
write(dst_fd, buffer, bytes_read);
}
// 5、关闭两个文件
close(src_fd);
close(dst_fd);
printf("File copied successfully\n");
return 0;
}
程序剖析
open() 用于打开文件并返回一个文件描述符(一个整数编号),后续的 read()、write()、close() 等操作通过这个文件描述符来访问对应的文件或设备。
下面的 0644 是在设置新文件的权限:
dst_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
我们把它拆开看:
所以 0644 的意思就是:-rw-r--r-- (最常见的普通文件权限):文件拥有者可以读、写;同组和其他人都只能读,不能写。
整个程序的核心:
while ((bytes_read = read(src_fd, buffer, sizeof(buffer))) > 0)
{
write(dst_fd, buffer, bytes_read);
}
bytes_read = read(src_fd, buffer, sizeof(buffer):从 src_fd 代表的文件读取数据,存入 buffer,最多读取 1024 字节。返回值为读取到的字节数。当文件读完时,返回值为零(返回值可能是:1024-1024-398-0),循环结束。
write(dst_fd, buffer, bytes_read):把 buffer 的数据写入目标文件,写入字节数为bytes_read。
一句话总结
这份看似简单的文件拷贝程序,其实就是 Linux 系统编程最经典的“第一课”。
通过它,你理解并上手了:
- 「一切皆文件」的核心哲学
- open / read / write / close 这套最基础、最强大的系统调用组合
- 文件描述符的概念与错误处理的基本思路
- 块拷贝的循环模式(后续串口、socket、设备驱动交互几乎都是这个结构)
道阻且长,行则将至,继续加油吧!