文件系统
- 磁盘
- 磁盘的物理结构
- 磁盘的存储结构
- 磁盘的逻辑抽象结构
- 对磁盘组进行管理
- 创建和删除文件时,`os`做了什么?
- 创建一个文件时,`os`做了什么?
- 删除一个文件,`os`做了什么?
- 制作软硬链接
- 软连接和硬链接区别
- 制作静、动态库
- 使用动静态库
- 使用静态库
- 使用动态库
磁盘
文件打开后,会加载到内存中,那么没有又打开的文件在哪里呢?
大量的文件,就在磁盘上
磁盘的物理结构
![]()
磁盘中有若干个光盘,磁头,在光盘中间有一个马达,每一个磁盘面都有一个磁头,我们的文件数据就在磁盘面上存储,访问磁盘上的文件,就是通过马达的旋转,和磁头的摆动进行寻址
磁盘的存储结构
在一个磁盘面上有若干个磁道,一个磁道有若干个扇区,数据就是存储在一个个扇区中,每一个扇区的存储容量为512字节
读写磁盘时,磁头找的是某一个面的某一磁道的某一个扇区,就能找到文件对应的数据
磁盘的基本单位是一个扇区,但我们访问以8个扇面(
4kb
)访问
磁盘的逻辑抽象结构
对磁盘进行管理,就是要先描述后组织,那么我们把磁盘上每一个扇面抽象成数组的一个单元,因为一般是以8个扇面来访问的,所以我们把磁盘抽象成数组,每一个单元大小是
4kb
我们管理磁盘时,要对磁盘进行分区,在对每一个分区进行分组,分而治之,管理每一个磁盘组
对磁盘组进行管理
上图是一个磁盘的一个分区,Block group是这个分区的一个磁盘组
在
linux
中文件的属性和数据是分开存储的
Data blocks
:存储文件的数据(以块为单位(一个单位容量为4kb
),存储文件的数据,一个文件可能使用多个块)
Block Bitmap
:通过位图标识Data bLocks
每一个块的使用情况比如:00001001 表示 第0个块,第3个块已被使用
inode Table
:以128字节为单位,存储的是文件的属性,也是数组的形式,每一个块存储一个文件的文件属性(每个文件属性中都有一个inode
来标识文件的唯一性(inode
在分区内唯一))
inode Bitmap
:inode Table
块的使用情况
Group Descriptor Table
:有多少inode
,起始的inode
编号,有多少个inode
被使用,有多少block
被使用,还剩多少
SB(super block)
:文件系统的等层数据结构,存储这个分区的相关属性(在多个磁盘组中都有,为了恢复数据使用)一个文件只有一个
inode
,但是一个文件可能使用多个数据块,如何标识那些数据块属于这一个文件?在
inode Table
中每一个块,存储一个文件的属性,在一个块中有一个数组block[15]:在这个数组的[0,11]中直接保存存放该文件数据的数据块的编号,在[12,15]中也指向数据块,但是这个数据块中不存储该文件的数据,而是存储该文件对应的其他存储该文件数据的数据块编号(一级索引)
创建和删除文件时,os
做了什么?
首先,我们需要知道,目录也是文件,文件=内容+属性,目录文件的
inode
就存储目录的属性,而目录的数据块存储的是在该目录下的文件和inode
编号的映射关系(linux
标识文件是通过inode
编号,而不是通过文件名)
创建一个文件时,os
做了什么?
创建文件时,首先会在
inode bitmap
中寻找为0的inode编号
,将它置为1,在inode Table
中找到对应的inode
,把文件的属性写入,为该文件分配数据块,建立inode
和Data blocks的映射关系,将block bitmap中对应的标志位置为1,我们会得到文件的inode
编号,找到自己所处的目录,根据目录的inode
找到目录的数据块,将文件名和inode
编号映射关系写入到目录的数据块中。
删除一个文件,os
做了什么?
通过文件名在该目录的数据块中查找文件名和
inode编号
的映射关系,得到inode
编号将inode Bitmap
中该inode
编号对应置为0,将block Bitmap
中该文件对应的数据块置为0。
制作软硬链接
软连接和硬链接区别
由上图可知,软链接是一个独立的文件,
inode
编号不同(就相当于电脑桌面快捷方式,软链接文件中存放这个文件所在路径),而硬链接就是在目录下,给指定文件添加inode
和文件名的映射关系删除软硬连接使用
unlink
这个数表示的就是文件的硬链接数,就是有多少个文件和这个
inode
映射
为什么创建一个普通文件的硬链接数是1,而一个目录文件的硬链接数是2
如上图,在test中的
.
表示当前路径,映射test目录的inode
,该inode
就映射两个文件,
制作静、动态库
静态库(.a)
动态库(.so)
.PHONY:all all: libmythod.a libmythod.so libmythod.a:add.o hello.o ar -rc libmythod.a add.o hello.o //生成静态库 add.o:myadd.c gcc -c myadd.c -o add.o hello.o:myhello.c gcc -c myhello.c -o hello.o libmythod.so:add_s.o hello_s.o gcc -shared -o libmythod.so add_s.o hello_s.o //生成动态库 add_s.o:myadd.c gcc -fPIC -c myadd.c -o add_s.o //-fPIC 生成与地址无关的.o文件 hello_s.o:myhello.c gcc -fPIC -c myhello.c -o hello_s.o .PHONY:lib lib: mkdir -p lib-static/include mkdir -p lib-static/lib cp *.h lib-static/include cp *.a lib-static/lib mkdir -p lib-dyl/include mkdir -p lib-dyl/lib cp *.h lib-dyl/include cp *.so lib-dyl/lib .PHONY:clean clean: rm -f *.o *.a *.so
使用动静态库
使用静态库
静态链接使用静态库,就是将静态库拷贝到程序当中
直接
#include“myadd.h”
,找不到头文件,头文件的搜索路径是在1、当前路径下2、系统的头文件路径下
解决:
将自己的库文件和头文件拷贝到系统路径下(系统路径:头文件(
usr/include/
)库文件(lib64/
))(找到头文件)
usr/include/
lib64/
指定使用哪一个库 (
gcc -l
第三方库)gcc mytest.c -lmythod
我们不推荐使用上面这种方法,这会污染系统
我们可以指定头文件和库文件的搜索路径
gcc mytest.c -o mytest -I ./lib-staic/include/ -L ./lib-static/lib/ -lmythod
使用动态库
动态链接使用动态库,通过地址将动态库和程序进行关联,不用进行拷贝
使用动态库的两种方法
把头文件和库放进系统路径下(和静态库第一种方法一样,不推荐)
编译时指定头文件,库的路径哪一个库
编译时能够找到库,但是进程运行时找不到依赖的库,静态链接将静态库拷贝到程序中,在运行时就不需要依赖库,而动态链接没有拷贝,在运行时就需要依赖库
如何让进程运行时找到动态库?
将动态库拷贝到
lib64/
环境变量
通过导入环境变量的方式–程序运行时,会在环境变量中查找自己需要的动态库路径–
LD_LIBRARY_PATH
配置文件
把库对应的软链接放在
lib64
中
如下图所示,可执行程序与动态库是分开加载的,动态库加载到物理内存中,映射到虚拟内存的共享区,多个进程可依赖于同一个动态库,可执行程序运行时,需要使用动态库时,会跳转到动态库,执行动态库代码,之后,再回到可执行程序,继续执行可执行程序的代码