看似简单的文件拷贝,却藏着 Linux 系统编程的核心思维

0 阅读2分钟

宏观理解

我们的目标是在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);

我们把它拆开看:

image.png

所以 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、设备驱动交互几乎都是这个结构)

道阻且长,行则将至,继续加油吧!