第三章 文件操作
3.1 Linux 文件结构
3.1.1 目录
文件系统
Linux 文件系统(ext4)把磁盘分为三个部分, super block/inode table/data block
inode
ext4可以简单理解为多级索引, inode就是索引节点.
inode 包含了文件的以下基本信息:
- 文件的字节数
- inode 编号
- 文件拥有者的 Uid
- 文件所属group的 Gid
- 文件的读、写、执行权限
- 文件的时间戳,共有三个:
- change:inode 上一次变动的时间
- modify:文件内容上一次变动的时间
- access:文件上一次打开的时间
- 链接数,即有多少文件名指向这个 inode
- 文件数据 block 的位置
➜ ~ stat a.txt
文件:a.txt
大小:0 块:0 IO 块:4096 普通空文件
设备:805h/2053d Inode:5767399 硬链接:1
权限:(0664/-rw-rw-r--) Uid:( 1000/ tian) Gid:( 1000/ tian)
最近访问:2022-09-26 14:02:37.937915997 +0800
最近更改:2022-09-26 14:02:37.937915997 +0800
最近改动:2022-09-26 14:02:37.937915997 +0800
创建时间:2022-09-26 14:02:37.937915997 +0800
普通文件和目录文件
普通文件, 文件名和inode一一对应, 硬链接是多个文件名指向一个inode, 软链接inode不同, 但是软链文件不保存实际内容, 只保存指向文件的路径, 相当于快捷方式.
目录文件包含多个目录项,每个目录项包含文件名和inode号
3.1.2 文件和设备
常见的文件类型
-
普通文件类型: Linux中最多的一种文件类型, 包括 纯文本文件(ASCII);二进制文件(binary);数据格式的文件(data);各种压缩文件。第一个属性为 [-] 。
-
目录文件类型: 在linux中,它的思想是一切皆是文件,目录文件也就是Windows中的目录,也就是能用 cd 命令进入的。第一个属性为 [d],例如 [drwxr-xr-x]。
-
字符设备文件: 即串行端口的接口设备,例如键盘、鼠标等等。第一个属性为 [c]。
-
块设备文件: 即存储数据以供系统存取的接口设备,简单而言就是硬盘。例如一号硬盘的代码是 /dev/hda1等文件。第一个属性为 [b]。
-
套接字文件: 这类文件通常用在网络数据连接。可以启动一个程序来监听客户端的要求,客户端就可以通过套接字来进行数据通信。第一个属性为 [s],最常在 /var/run目录中看到这种文件类型。
-
管道文件: FIFO也是一种特殊的文件类型,它主要的目的是,解决多个程序同时存取一个文件所造成的错误。FIFO是first-in-first-out(先进先出)的缩写。第一个属性为 [p]。
-
链接文件: 类似Windows下面的快捷方式。第一个属性为 [l],例如 [lrwxrwxrwx]。
3个重要的设备文件
- /dev/console
- /dev/tty
- /dev/null
3.2 系统调用和设备驱动程序
- open
- read
- write
- close
- ioctl
3.3 库函数
使用系统调用进行输入输出会导致效率非常低, 内核态和用户态切换
Unix I/O和C标准库I/O函数压根不是一码事。
Unix I/O也叫低级I/O,也叫Unbuffered I/O,是操作系统内核部分,也是系统调用;
而C标准I/O函数相对也成Buffered I/O,高级I/O,一般是为了效率考虑对这些系统调用的封装。
3.4 底层文件访问
每个进程有几个与之关联的文件描述符, 文件描述符是一个非负整数, 本质上是一个索引值
在进程A中,文件描述符1和30都指向了同一个打开的文件句柄(标号23)。这可能是通过调用dup()、dup2()、fcntl()或者对同一个文件多次调用了open()函数而形成的。
进程A的文件描述符2和进程B的文件描述符2都指向了同一个打开的文件句柄(标号73)。这种情形可能是在调用fork()后出现的(即,进程A、B是父子进程关系),或者当某进程通过UNIX域套接字将一个打开的文件描述符传递给另一个进程时,也会发生。再者是不同的进程独自去调用open函数打开了同一个文件,此时进程内部的描述符正好分配到与其他进程打开该文件的描述符一样。
此外,进程A的描述符0和进程B的描述符3分别指向不同的打开文件句柄,但这些句柄均指向i-node表的相同条目(1976),换言之,指向同一个文件。发生这种情况是因为每个进程各自对同一个文件发起了open()调用。同一个进程两次打开同一个文件,也会发生类似情况。
struct file 是属于系统级别的结构,换句话说是可以共享与多个不同的进程。
从姿势上来讲,用户 open 文件得到一个非负数句柄 fd,之后针对该文件的 IO 操作都是基于这个 fd ;
文件描述符 fd 本质上来讲就是数组索引,fd 等于 5 ,那对应数组的第 5 个元素而已,该数组是进程打开的所有文件的数组,数组元素类型为 struct file;
结构体 task_struct 对应一个抽象的进程,files_struct 是这个进程管理该进程打开的文件数组管理器。fd 则对应了这个数组的编号,每一个打开的文件用 file 结构体表示,内含当前偏移等信息;
file 结构体可以为进程间共享,属于系统级资源,同一个文件可能对应多个 file 结构体,file 内部有个 inode 指针,指向文件系统的 inode;
inode 是文件系统级别的概念,只由文件系统管理维护,不因进程改变( file 是进程出发创建的,进程 open 同一个文件会导致多个 file ,指向同一个 inode );
3.5 标准io库
标准IO库就是C语言里的stdio.h
包括下列函数:
- fopen/fclose
- fread/fwrite
- printf/fprintf
- scanf/fscanf
3.7 文件和目录的维护
Linux还提供了 chmod/chown/mkdir
等一些系统调用, 大多需要#include<unistd.h>
和#include<sys/stat>
等头文件.
3.10 proc文件系统
Linux系统上的/proc目录是一种文件系统,即proc文件系统。
与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。