持久存储设备(如硬盘、固态硬盘)在断电时能保持数据不变。操作系统通过文件系统管理持久存储,提供了两个关键抽象:文件和目录。
核心抽象
- 文件 (File):一个线性字节数组。每个文件拥有一个低级名称(通常称为 inode 号)。
- 目录 (Directory):一种特殊的文件,其内容是一个包含
(用户可读名字, 低级名字)对的列表。目录通过包含其他目录形成任意层级的目录树 (Directory Tree)。
文件操作 API
创建文件
通过 open() 系统调用创建文件,返回一个进程私有的文件描述符 (File Descriptor)。文件描述符是一个整数,作为访问文件的句柄。
int fd = open("foo", O_CREAT | O_WRONLY | O_TRUNC);O_CREAT:创建新文件。O_WRONLY:只写模式。O_TRUNC:若文件存在则截断为 0 字节。
读写文件
使用 read() 和 write() 进行顺序访问。进程默认打开 3 个文件描述符:0(标准输入)、1(标准输出)、2(标准错误)。
// read 返回读取的字节数
read(fd, buffer, size);随机访问
使用 lseek() 改变文件读写的当前偏移量。
off_t lseek(int fildes, off_t offset, int whence);whence决定偏移基准:SEEK_SET(文件开头)、SEEK_CUR(当前位置)或SEEK_END(文件末尾)。- 注意:
lseek()仅改变操作系统内存中维护的偏移量变量,不会直接触发磁盘的物理寻道 (Disk Seek)。
强制同步写入
write() 调用通常只将数据写入内存缓冲区。为了保证数据持久化(如数据库应用),需调用 fsync() 强制将脏数据写入磁盘。
int rc = write(fd, buffer, size);
rc = fsync(fd); // 强制写入磁盘为确保文件在目录中的元数据也持久化,有时还需对包含该文件的目录调用 fsync()。
文件重命名
rename(char *old, char *new) 提供原子 (Atomic) 更新保证。系统崩溃时,文件要么是旧名称,要么是新名称。常用于安全更新文件:将新内容写入临时文件,调用 fsync(),最后 rename 覆盖原文件。
获取文件元数据
使用 stat() 或 fstat() 获取文件的元数据(如大小、inode 号、权限、时间戳),这些信息通常保存在文件系统的 inode 结构中。
struct stat {
ino_t st_ino; /* inode number */
off_t st_size; /* total size, in bytes */
// ... 其他元数据
};删除文件
删除文件的系统调用是 unlink()。文件系统通过引用计数 (Reference Count / Link Count) 跟踪链接到特定 inode 的文件名数量。unlink() 会移除文件名与 inode 的链接并递减引用计数。只有当引用计数降为 0 时,文件系统才会真正释放 inode 和数据块。
目录操作 API
目录的格式被视为文件系统元数据,只能通过系统调用间接更新。
- 创建目录:
mkdir()。新创建的空目录包含两个默认条目:.(自身)和..(父目录)。 - 读取目录:使用
opendir()、readdir()和closedir()遍历目录条目。
DIR *dp = opendir(".");
struct dirent *d;
while ((d = readdir(dp)) != NULL) {
printf("%d %s\n", (int) d->d_ino, d->d_name);
}
closedir(dp);- 删除目录:
rmdir()。为了防止意外删除大量数据,rmdir()要求目录必须为空。
硬链接与符号链接
硬链接 (Hard Link)
通过 link()(命令行 ln)创建。硬链接在目录中创建一个新名称,指向与原文件相同的 inode 号。
- 限制:不能对目录创建硬链接(防止目录树成环),不能跨文件系统链接。
符号链接 (Symbolic Link / Soft Link)
通过 ln -s 创建。符号链接是文件系统中的第三种对象类型(类型标记为 l)。
- 链接文件的数据是其指向的目标文件的路径名(因此链接文件的大小等于路径字符串的长度)。
- 允许悬空引用 (Dangling Reference):如果原文件被删除,符号链接依然存在,但指向无效路径。
文件系统的创建与挂载
- 创建:
mkfs工具在目标设备分区(如/dev/sda1)上写入一个空的指定类型(如 ext3)文件系统。 - 挂载:
mount程序将底层文件系统粘贴到现有目录树的挂载点 (Mount Point) 上,将多个独立的文件系统统一到单一的目录树命名空间中。