Skip to content

文件系统

“裸奔”层次:不带操作系统编程

层级说明
APP应用层
Hardware硬件层

特点

  • 简单粗暴:应用层直接操作硬件(寄存器、IO口等)。

缺点

  • 开发需理解原理图和硬件细节。
  • 仅支持单任务运行,无法并发。

带操作系统的编程

层级说明
APP应用层
OS操作系统
Hardware硬件层

特点

  • 开发聚焦应用逻辑,无需关心硬件细节。
  • 支持多任务并发运行。

缺点

  • API数量庞大。
  • API功能可能不符合特定需求。

操作系统(OS)定义

  • 直接运行在“裸机”上的基础系统软件,所有应用软件依赖其支持。 常见操作系统
  • Windows(x86/xp/win8/win10/win11)
  • Linux(Ubuntu/CentOS/RedHat/Kali)
  • macOS
  • iOS
  • Android
  • 鸿蒙
  • Unix

Linux开发特点

  • 通过调用Linux提供的系统API接口操作硬件或使用系统服务。

Linux文件系统

核心理念:一切皆文件。所有操作通过文件接口实现。

文件系统组成

文件系统是存储、组织、管理和提供访问文件的一套方式、方法、协议及软件实现。

文件

  • 文件属性:由 inode(索引节点)管理,存储文件元数据(权限、大小等)。
  • 文件内容:实际存储的数据。

文件操作过程

  1. 硬链接:通过文件名找到对应 inode
  2. 内核数据结构
    • struct inode:描述文件的物理信息(内核创建)。
    • struct file:描述已打开文件的状态(如文件偏移量)。
    • 一个文件可被多个应用打开,每个打开操作对应独立的 struct file
  3. 操作流程
    plaintext
    进程文件表项 → struct file → struct inode → 硬件inode → 文件内容

进程文件表项

每个进程维护一个文件指针数组(struct file* [])。

  • 文件描述符(fd):数组下标,标识打开的文件。
    • open() 返回 fd,后续操作通过 fd 访问文件。

系统IO函数

  • open(), read(), write(), close() 等由操作系统提供的文件操作接口。

Linux系统IO操作

打开文件:open()

函数原型

c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

// 版本1
int open(const char *pathname, int flags);

// 版本2(创建文件时)
int open(const char *pathname, int flags, mode_t mode);

参数说明

  • pathname:文件路径(含文件名和扩展名)。
  • flags:打开方式标志位:
    • O_RDONLY:只读
    • O_WRONLY:只写
    • O_RDWR:可读可写
    • O_CREAT:文件不存在时创建(需配合 mode 参数)。
  • mode:文件权限(八进制数,如 0777)。实际权限 = mode & ~umask

返回值

  • 成功:文件描述符(fd)。
  • 失败:-1

读取文件:read()

函数原型

c
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

参数说明

  • fd:文件描述符(open() 返回)。
  • buf:存储读取数据的内存地址指针。
  • count:需读取的字节数。

返回值

  • 成功:实际读取的字节数。
  • 失败:-1

写入文件:write()

函数原型

c
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

参数说明

  • fd:文件描述符。
  • buf:待写入数据的内存地址指针。
  • count:需写入的字节数。

返回值

  • 成功:实际写入的字节数。
  • 失败:-1

移动文件光标:lseek()

函数原型

c
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);

参数说明

  • fd:文件描述符。
  • offset:偏移字节数(正数向文件尾,负数向文件头)。
  • whence:基准位置:
    • SEEK_SET:文件开头
    • SEEK_CUR:当前位置
    • SEEK_END:文件末尾

返回值

  • 成功:实际偏移的字节数。
  • 失败:-1

注意:偏移超出文件末尾形成“空洞”,写入时填充空洞。

关闭文件:close()

函数原型

c
#include <unistd.h>
int close(int fd);

参数说明

  • fd:需关闭的文件描述符。

返回值

  • 成功:0
  • 失败:-1

文件权限与 umask

权限计算规则

  • 实际权限 = 指定权限 & ~umask。示例:
    plaintext
    指定权限:0777
    umask:0022
    实际权限:0777 & ~0022 = 0777 & 0755 = 0755

设置 umask

函数原型

c
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);

参数说明

  • mask:新的权限掩码值。

返回值

  • 旧的 umask 值。

注意:代码中的 umask 设置不影响系统全局设定。


作业

实现文件拷贝功能:将文件A的内容完整复制到文件B(B为空文件)。

步骤

  1. open() 打开源文件(A)和目标文件(B)。
  2. 循环调用 read() 从A读取数据到缓冲区。
  3. 调用 write() 将缓冲区数据写入B。
  4. close() 关闭两个文件。

总结

  • 系统IO:Linux通过文件描述符抽象文件操作。
  • 核心函数openreadwritelseekclose 实现完整文件管理。
  • 权限控制umask 调节文件创建时的实际权限。

知识如风,常伴吾身