文件系统的了解阶段
当文件没有打开的时候,那么文件存储在磁盘之中。
既然存储在磁盘中,那么我们就要去了解一下磁盘文件的存储
磁盘由多个盘片和多个读写头组成,每个盘面都有两个表面,且每一个表面都可以存储数据。
对于每个盘面来说,每个盘面形成半径不同的同心圆,两个圆之间形成的就是磁道。
磁道又在一次被分割,一个磁道又被划分成一个个扇区。
扇区通常包括512字节的数据。扇区就是磁盘的基本单位
虽然磁盘的基本单位是扇区(512字节),但是比较小,而且有可能不同的生产商给出的扇区的大小可能本不一样,所以操作系统(文件系统)和磁盘进行I/O操作的基本单位的块
块是对磁盘存储和访问的抽象,块通常是一个连续的、固定大小的抽象单元。通常是512字节的整数倍。
块通常由下面几个部分构成:
Block Group:ext2文件系统根据分区的大小划分为数个快组BlockGroup。,且每一个BlockGroup都有着相同的结构
Block Group分为:
超级块:存放文件系统本身的结构信息。记录的信息主要有,block和inode的总数,使用了多少block和inode的数量,,block和inode的大小,等等。——可以查资料看看
GDT:块组描述符
块位图:哪些数据块被占用
inode位图:inode是否被占用
inode节点表:存放文件属性
数据区:存放文件的内容
我们知道inode和数据是映射关系,是一种一对多的映射关系——存在软硬链接。为什么这么说看下文
一个目录下,可以有很多文件,但是这些文件都没有重复的文件名!
数据区存储的是文件的内容,没有存储文件名的地方,那么文件名存储在哪里呢?
还有一个问题就是目录是文件吗?
显然是的,因为目录它也要自己的inode号,也有自己的数据区。而目录的数据区就是存储的该目录下所有文件的名字。
这就对应了我们之间讲的,进入一个目录要具有什么权限。
x权限,因为用户要进入目录
如果用户要想在该目录下创建文集或者目录,就需要拥有w权限,因为目录的数据区要进行写入新建的文件名或者目录名。
下面有三个问题:
创建文件,系统做了什么?——为该文件分配inode和数据区,进行inode和数据区的映射关系,在该文件的目录的数据区中写入该文件的名字。
删除文件,系统做了什么?——删除inode和数据区的映射关系,数据区本身是没有被改变什么的,删除该文件目录下数据区的文件名。
查看文件,系统做了什么?——把该文件的属性信息安装用户的查看方式显示出来。
思考——为什么下载软件比卸载慢呢?
因为下载是真实的把数据写到磁盘中,而卸载只要把inode和数据直接的链接断开就可以,不需要把数据清空,再次下载其他软件的时候,只需要进行数据的覆盖就可以。
数据的恢复就是利用数据没有被删除这个原理,但在恢复数据之前,最好不要下载安装什么东西,导致数据被覆盖修改而不能被恢复。
软硬链接
软链接
命令:ln -s 原始文件路径 软链接的文件路径
软链接有什么特定呢?
- 有自己的inode,文件里面的内容是指向原文件对应的路径。就是相当于windows下面的快捷方式。
下面是创建软链接
- 先创建test.c文件
我们知道,如果不指定test的路径,就不能运行此可执行程序,在前面的文章中,可以把此可执行文件放在环境变量中,就可以执行
如果不放入环境变量中呢?
可以用软链接
把当前文件所在的绝对路径进行软链接到上级路径
那么就可以直接在上级目录运行了。
硬链接
命令:ln 原始文件路径 硬链接的文件路径
硬链接没有独立的inode,硬链接创建的文件并不是真正意义上的文件,它主要就是在指定的目录下创建了一个映射而已。
下面演示硬链接:
ln test.c test1.c ln test.c test2.c ln test.c test3.c
我们发现他们的inode都是一样的,就验证了我们之前说的情况了。
这里的4是什么意思呢?——4显然表示有4个inode,这是用来计数的,当inode的个数为0的时候,就是真正的把该文件删除了。
思考:为神马默认创建的目录的计数是2呢?
其实有一个隐藏的文件**.**
所以就有2个了。
.
表示的就是当前目录。
动静态库
静态库以.a
后缀结尾,动态库以.so
后缀结尾
静态库其实链接的时候是直接把代码拷到我们的可执行代码里面的。
而动态库只是链接到我们的可执行程序中。
找动态库,只需要在改好代码处加上偏移量,就可以找到共享库。
静态库
我们有很多.c.h文件,当我们编译它的时候,会很麻烦。
下面我们就要把他们制成静态库。
先把他们编译成.o文件
打包——ar -rc libmylib.a .o文件
**注意:**库的写法:前缀必须是lib开头的,后缀必须以.a结尾。去到前后缀就是库的名字。
gcc默认的搜索路径是:/usr/include
库文件的默认搜索路径是:/lib64 或者 /usr/lib64
我们可以把静态库的头文件以及库文件拷贝到gcc的默认搜索路径下;但是这样会污染里面的库文件。
可以用下面这个路径:
gcc main.c -I ./MyLib/clude/ -L ./MyLib/lib/ -lmylib
解释一下:
-I是指定头文件的路径
-L是指定库文件的路径
-l(这个是小L)是指明库文件路径下的哪一个库。
动态库
为什么使用动态库?
使用动态库,可以节约内存空间
可以提高运行速度
可维护,更改的时候,只改变库文件就行,不需要重新编译
共享,多个程序可以共享同一个动态库
制作动态库
形成.o文件,加上选项fPIC,fPIC作用就是产生位置无关码
用gcc命令对.o文件进行打包生成动态库。gcc -shared 由上一步生成的.o文件 -o 动态库
上面我们就制作好了动态库。
gcc默认是链接的动态库。
如果我们直接按照静态库的方法进行运行,发现不可以运行成功。
gcc main.c -I ./MyLib/clude/ -L ./MyLib/lib/ -lmylib
把生成的a.out运行,发现报错。
我们不是告诉gcc我们的库的位置了吗?为什么还报错呢
原因就是我们是告诉gcc的,没有告诉操作系统或者说是链接器。那么我们运行的时候就会报找不到共享库。
下面是设置动态库路径的几种方式:
直接把库拷贝到/lib64路径下面——不建议
更改环境变量LD_LIBRARY_PATH,在该路径下面再添加一个你的动态库的路径。一但重启服务器,该环境变量看就没有了,因为它是内存级别的环境变量。
修改库的配置文件:配置/etc/ld.so.conf.d/,在该文件下随便创建一个.conf的文件,把动态库的路径写到哪个文件中,然后用ldconfig更新一下的。需要管理员权限
动静态库制作的命令集合
.PHONY:all all:libmylib.so libmylib.a libmylib.so:file1dy.o file2dy.o gcc -o libmylib.so -shared file1dy.o file2dy.o file1dy.o:file1.c gcc -o $@ -c -fPIC $^ file2dy.o:file2.c gcc -o $@ -c -fPIC $^ libmylib.a:file1.o file2.o ar rc libmylib.a file1.o file2.o file1.o:file1.c gcc -o $@ -c $^ file2.o:file2.c gcc -o $@ -c $^ .PHONY:MyLib MyLib: mkdir -p ../MyLib/lib mkdir -p ../MyLib/clude cp *.a ../MyLib/lib cp *.so ../MyLib/lib cp *.h ../MyLib/clude .PHONY:clean clean: rm -f *.o *.a hello *.so