基础 I/O
打开文件本质是进程打开文件
操作系统内部存在大量被打开的文件, 这些文件需要被操作系统管理起来, OS内部需要一个描述文件属性的结构体
操作文件本质:进程操作文件
文件刚开始时在磁盘上,需要os操作文件
linux系统 open函数
1 2 3 4 5 6 7 8
| #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); # flags 标记位传参, 用比特位进行标志位的传递 OS很多系统调用接口的常见设计方法 # 本质是一个位图(使用二进制位(0和1)来表示数据或资源状态的数据结构)
|
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h>
const char* filename = "log.txt";
int main() { int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (fd < 0) { perror("open"); return 1; } const char* message = "hello linux\n"; write(fd, message, strlen(message)); close(fd); }
|
文件描述符 fd
内核的进程和文件映射关系的数组的下标
open:
1 2 3 4 5
| 创建 file 开辟文件缓冲区的空间 查进程的文件描述符表 file地址, 填入对应的表下标中 返回下标
|
linux系统一切皆文件
重定向 & 缓冲区
观察代码结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> const char* filename = "log.txt";
int main() { close(1); int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (fd < 0) { perror("open"); return 1; } printf("printf, fd: %d\n", fd); fprintf(stdout, "fprintf, fd: %d\n", fd); fflush(stdout); close(fd); }
|
stdout 中文件描述符的下标就是1
注释部分的原因是, 存在语言级别的缓冲区。printf写到了这个缓冲区中, 程序结束时, 会通过 1 号文件描述符像1号文件刷新内容, 所以close(fd) 之后1号描述符被关闭了。
重定向 dup
dup2(fd, 1)
1 2 3 4 5 6 7
| int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
dup2(fd, 1);
printf("hello world\n"); fprintf(stdout, "hello world\n");
|
进程替换不会影响进文件描述符表
文件系统
存在非常多的文件, 没被打开的文件存在磁盘(通过磁贴特性,写入01数据)。
通过文件路径 + 文件名 找到磁盘中的文件
磁盘的存储结构
磁盘是一个机械设备,外设(速度相对内存非常慢
磁盘的表面被划分为一个个磁道, 磁道中也分为一个个扇区, 一个扇区为 512B
1片 = n 磁道, 1 磁道 = m 扇区
如何找到指定位置的扇区:磁针 -> 磁道 -> 扇区(CHS)
为了方便对磁盘的管理, 把磁盘划分为一个个扇区组成的数组 sector disk_array[N], 通过数组的下标(经过一系列计算)定位 CHS, 访问磁盘。
一般而言, OS 未来和磁盘交互的时候 基本单位是 八个连续扇区(块大小), 4KB
文件 = 多个块组成
磁盘文件系统
Data block 数据区, 存放文件内容
1
| 数据区是磁盘上用于实际存储文件数据的部分。它由多个大小相等的数据块组成,每个数据块可以存储文件的一部分内容。文件系统将这些数据块分配给文件使用,并通过特定的方式记录哪些数据块已被使用,哪些仍然空闲。
|
块位图 : 通过比特位内容,表示Data block区整体使用情况
1
| 块位图是一种用来跟踪数据区中哪些块已经被使用,哪些块仍然是空闲的方法。它通常是一个位数组,其中每一位对应于数据区中的一个块。如果某一位被设置为1,则表示对应的块已经被分配出去;若为0,则表示该块未被使用。这种方法使得文件系统能够高效地找到可用的块来存储新数据或扩展已有文件。
|
inode table:存放文件的属性(大小,所有者… 是一个大小固定的集合体
1 2 3 4 5 6
| Inode是指在Unix和类Unix文件系统(如ext2, ext3, ext4)中,用于存储文件元数据的数据结构。每一个文件都有一个与之关联的inode,它包含文件的属性信息,但不包括文件名和文件数据。inode中存储的信息包括: 文件的权限(读、写、执行) 文件的所有者和组 文件的大小 文件的创建时间、修改时间和访问时间 文件的数据块指针(直接指向数据块或者间接指向其他索引块)
|
inode位图
1 2 3 4 5
| Inode位图是文件系统中用于记录哪些inode已经被使用,哪些是空闲的的一种数据结构。
它是一个位数组(bit array),每一位对应一个 inode。 如果某一位是 1,表示对应的 inode 已被使用; 如果是 0,表示该 inode 未被使用,可以分配给新文件或目录。
|
目录 = 文件属性 + 文件内容, 目录文件中存放inode和文件名的映射关系。
删除文件
1 2 3
| 更新inode表,将inode标记为未使用。 更新块位图,将文件占用的数据块标记为空闲。 实际存储的数据不会立即从磁盘上物理删除,而是等到这些空间被再次写入新数据时才真正被覆盖。
|
软硬链接
理解一个程序如何加载进入内存中的
软连接 具有自己的新inode
硬链接 链接出来不是一个独立的文件,与目标文件共用inode, 属性中有一系列硬链接
为了避免形成路径环绕, 不允许对目录建立硬链接
动静态库
看下面代码
1 2 3 4 5 6 7 8 9
| #include <stdio.h> #include <string.h>
int main() { char buffer[1024]; strcpy(buffer, "hello world\n"); printf("%s\n", buffer); return 9; }
|
编译这个文件形成 可执行文件 a.out
1 2 3 4 5
| ldd a.out 显示 linux-vdso.so.1 (0x00007ffe92df5000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f91493d8000) /lib64/ld-linux-x86-64.so.2 (0x00007f91495fa000)
|