Linux文件系统,软硬连接,动静态库

Posted 小峰同学&&&

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux文件系统,软硬连接,动静态库相关的知识,希望对你有一定的参考价值。

  1. 前提知识

当我们的文件没有被打开的时候,只能在磁盘放着,磁盘上有大量的文件,这么多文件,也是要被静态管理起来的,方便我们随时打开。

1.1.磁盘的物理结构

1.磁盘是我们计算机中唯一的一个机械结构。

2.磁盘是一个机械结构,而且还是一个外设,所以相比一CPU他就很慢很慢。

3.现在我们使用的笔记本电脑,已经很少用磁盘(HDD)了。用的是固态硬盘(SSD)。

4.在企业端,磁盘依旧是存储的主流。一般是SSD和HDD混和使用。

因为磁头和盘面的的距离很近很近,所以磁盘要防止抖动防止灰尘。所以磁盘的密封性能一定很好。

1.2.磁盘的存储结构

1.3.磁盘的逻辑结构

1.3.1.OS对磁盘的方法单位

1.3.2.OS对磁盘IO过程的优化

可以stat “文件名”:查看文件具体信息
  1. 文件系统

2.1.前提知识

对文件属性和文件内容的认识:

2.2.Linux文件系统

Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的。

Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子
超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏(一般有备份),可以说整个文件系统结构就被破坏了。
GDT,Group Descriptor Table:块组描述符,描述块组属性信息,有兴趣的同学可以在了解一下
块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用
inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
inode节点表(inode table):存放文件属性 如 文件大小,所有者,最近修改时间等
数据区(data blocks):存放文件内容

磁盘格式化就是重新写入文件系统。

2.3.读取工作过程

1.先获得文件inode--》 2.通过inode信息获得数据块的下标---》3.完成读取操作

2.4.目录文件

2.5.添加文件

1. 存储属性

内核先找到一个空闲的i节点(这里是263466)。内核把文件信息记录到其中。

2. 存储数据

该文件需要存储在n个数据块,内核找到了n个空闲块:300,500,800 --- 。将内核缓冲区的第一块数据复制到300,下一块复制到500,以此类推。

3. 记录分配情况

文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。

4. 添加文件名到目录(在目录中建立文件名和文件inode的映射关系)

新的文件名test.txt。内核将入口(263466,test.txt)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。

2.6.删除文件

删除文件很简单,只需要修改GDT(块组描述符)。数据块对应的位图结构(block bitmap)和inode对应的位图结构(inode bitmap)即可。其实不是真正意义删除,只是把原有的数据(inode和数据块)从开始的不可覆盖,变成了覆盖,不受保护了。

所以按理说我们删除文件后,知道删除文件的inode (通过日志信息)。只要那一块内存没有被覆盖 是有可能恢复的。

  1. 硬链接 和 软链接

3.1.硬链接

介绍

我们看到,真正找到磁盘上文件的并不是文件名,而是inode。其实在linux中可以让多个文件名对应于同一个inode。

touch test.txt :创建一个文件
ln test.txt hard_test.txt :给test.txt创建一个硬链接
ls -1i:查看文件对应的inode
这不就是给inode起一个别名嘛。

用法

也可以看看文件的inode

所以每一个目录下的 "." 和 ".." 就是硬链接。

这也就解释了为什么 'cd ..' 能回到上级目录。

特例

"." 和 ".." 就是硬链接,为什么我们不能给目录建立硬链接?
假如我们给根目录建立一个硬连接,当我们从根目录去查找某一个文件的时候,可能就会生成一个闭环,死循环了。

3.2.软链接

介绍

硬链接是通过inode引用另外一个文件,软链接是通过名字引用另外一个文件,所以软连接标定一个文件不是通过文件的inode编号,而是通过文件名称。

ln -s test.txt soft_test.link :给test.txt创建软链接
这不就是win下的快捷方式嘛。

用法

指向别的可执行程序。(快捷方式)

3.3.ACM时间

  1. 动态库和静态库

4.1.特征介绍

静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库
动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间

先来一段测试代码:

一起我们写项目的时候,都会这样使用,在main.c包含各自运用到函数的头文件,然后全部的“xxx.c"文件一起编译,即可编译完成。
这是我们的以前学到的,头文件和源文件基本使用。、
也可以分开编译最后再链接
可以看到一样可以形成可执行文件。
所以我们只给别人提供可重定向目标二进制文件和对应的头文件,就可以给别人提供我们的函数使用。
这种思想就已经是库的思想了。
将所以的“xxx.o”文件打包,形成库,提供给对方一个库文件和全部的头文件即可。

打包就是将多个“xxx.o”文件合起来形成一个文件,这就是库文件。

根据打包方法的不同,分为静态库和动态库。

4.2.生成静态库

ar -rc 【生成的库名称】 【全部的“xxx.o”文件】
//ar是gnu归档工具,rc表示(replace and create)(替换并创建)

直接创建一个makefile自动化文件。

查看生成静态库:

ar -tv 【库文件】:查看库文件是由那俩个文件
t:列出静态库中的文件
v:verbose 详细信息

交付库的时候:

1.提供:“xxx.a”/“xxx.so”文件;
2.提供对应匹配的 “xxx.h”文件。

一般都会打包好到一个目录,然后再压缩给别人。

4.3.使用静态库

安装的本质就是:把文件拷贝到知道系统能找到的目录下。

方法一:直接使用

gcc的链接规则:

1,gcc默认是动态链接(建议行为),对于特定的库,究竟是动态还是静态,取决于你提供的是动态库还是静态库。有动态库就动态链接。

2,有多个库的时候,一个一个链接的,可能一部分是动态链接,一部分是静态链接,只要有一个库是动态链接的,那里就会显示是动态链接。

方法二:安装到系统对应路劲下

建议测试完后立即卸载掉,我们自己写的程序放在系统的路劲下不安全。

卸载:就是把刚刚拷贝到系统默认路劲下的文件原封不动的删除掉。一定注意不要删错了。

4.4.生成动态库

交付库的时候:

1.提供:“xxx.a”/“xxx.so”文件;
2.提供对应匹配的 “xxx.h”文件。

一般会打包好到一个目录下,然后压缩好给别人

4.5.使用动态库

不能像静态链接那样世界使用,运行会找不到对应的动态库。

库的默认搜索路劲

1, 环境变量LD_LIBRARY_PATH
2, /usr/lib/(32位)或/usr/lib64/(64位)
3, /usr/local/lib/(32位) 或 /usr/local/lib64/(64位) (这个是用户级别的)
4, /lib64/

方法一:修改LD_LIBRARY_PATH环境变量

但是环境变量是内存级的,当我们重新链接我们的机器的时候他就不能再次执行了。因为环境变量改变了。如果像使环境变量不变就需要去修改配置文件了,比较麻烦。临时做测试可以。

方法二:安装进系统

方法三:配置文件(xxx.conf)

/etc/ld.so.conf.d/ 路劲下有很多的配置文件

动态库在进行搜索时,包含路劲的配置文件。

创建一个任意名称的xxx.conf 文件
给刚刚创建的配置文件写入,我们的动态库所在的目录(sudo添加)
然后更新一下:sudo ldconfig(一定要做)

这个和安装到系统一样的效果,再次链接还能使用。

删除配置文件的时候也要ldconfig

方法四:创建软连接

当前目录下建立软连接

系统目录下建立软连接

总结

我们能让可执行找到动态库文件的时候,我们再把头文件拷贝进系统,这样就只需指定 ”-l 库名“,即可完成编译任务 。运行时候不需要库文件,但是需要用到动态库(而且还要能找到)。

  1. 动静态库的加载

5.1.静态库

静态库一般不考虑加载过程

因为静态链接编译的时候,就已经将对应的实现加载到了可执行程序你内部,也就是说静态库,在编译完成后,就不需要库了。可执行程序需要的代码,已经被拷贝进去了。
会有代码冗余的现象:例如:每次调用printf,都需要加载一份priintf的实现。
编译是加载,到哪里呢?加载进了代码区。(建议复习进程地址空间)
拷贝进来的代码,必须通过相对确定的地址位置来进行访问。

拷贝进代码区,这里也就和我写的函数一样。采用绝对编址的方式。

5.2.动态库

静态链接:编译的时候在调用函数的位置完成实现代码的拷贝。(代码冗余)
动态链接:编译的时候在调用函数位置放入偏移量地址。
动态库是在使用的时候被加载进内存,然后映射到进程的共享区,确定start地址,然后在可执行程序中存放的是偏移量地址。start地址+偏移量地址确定虚拟地址,通过页表映射完成执行。

理解Linux—inode

文件系统

本篇文章接上一篇(Linux基础IO)。

理解文件系统首先来了解一下磁盘,下面看图片:

磁盘盘片:主要记录数据的部分
扇区:为最小的物理存储单位,扇区组成的圆就是柱面。

磁盘寻找文件的步骤:
1.先找哪个盘面
2.在找哪个柱面
3.最后确定在哪个扇区

经过以上的3个步骤就确定要读写的文件。

ext2文件系统inode

计算机如何管理好这些磁盘呢?答案是把磁盘分区。分区的头部有一个启动块(Boot Block),,该分区的其他区域会划分成一个个块组(Block Group)。

那我们管理好一个块组就可以了,其他的都是一样的。每个块组都有相同的结构组成:

Super Block:存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。
Group Descriptor Table:块组描述符,描述该分区中块组的属性信息
Block Bitmap:Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用
inode Bitmap每个bit表示一个inode是否空闲可用
inode Table:存放文件属性 如 文件大小,所有者,最近修改时间等
Data blocks:存放文件内容

创建文件的过程

把上面的图简化一下:

1.存储信息:
内核先找空闲的分区,块组,在分配inode,通过i节点表找到空闲的i结点(上面的文件是1845087),内核把文件信息记录到其中。
2.存储数据:
通过block bitmap找到空闲的块组,假如是300,500,900三个
3.将文件的内容分别存到data blocks中
4. 添加文件名到目录
新的文件名y.txt。linux如何在当前的目录中记录这个文件?内核将入口(1845087,y.txt)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。

2.查找文件

首先找到该文件的分区和块组,接着找到文件对应的inode编号,在inode table中拿到该文件的属性,在根据inode和data blocks的映射关系找到是哪个块,在到data blocks拿到文件的内容。这就是查找文件。

3.理解删除文件

删除文件并不是删除数据,例如我们下载一个16G的游戏我们下载的时间比较长但是删除的时候便会很快。
删除文件:找到文件的对应block bimap和inode bitmap中的位置,此时直接把对应的有效位置改为无效,找不到映射关系即可。

软硬链接

软连接

建立软连接命令:ln -s

我们用ll-ai查看一下,test和test.s的inode是不同的所以软连接是一个独立的文件

我们没删掉test,test.s可以运行,但干掉test够,文件虽然在但是已经不能运行了。

硬链接

建立软连接命令
ln:


我们看到硬链接的文件的inode和文件大小是一样的,

干掉test,但test.h还是一样可以运行的。

这里的链接数是硬链接,那为什么是2呢?

还有. 跟…,分别代表当前目录和上级目录,.和tmp的inode是一样的。.tmp跟它的inode,…跟它的inode,所以链接数是2。

软硬链接区别:

软连接是单独的文件,硬链接和指向的文件共享相同的inode,相当于重命名。硬链接反应了文件名和inode的对应关系。

三个时间


Access 最后访问时间
Modify 文件内容最后修改时间
Change 属性最后修改时间

动静态库

查看库命令:ldd

来查看一下Linux默认使用的库:

它使用的是动态库。
在来使用静态库看看:
在makefile中加上-static


动态链接生成的可执行文件比静态链接的要小的多。

原理


动态库:进程可以通过共享区,页表映射到物理内存,而静态库是直接放在代码区

动静态库区别:

动态库优点:体积小,依赖库。缺点:没有库则无法无运行
静态库优点:不依赖第三方库,移植性强 。缺点:体积大,浪费内存空间

静态库的打包和使用

为了更容易理解,创建4个文件,add.c,add.h和sub.c, sub.h

add.h内容

  1 #pragma onec
  2 
  3 int add(int a,int b);   

add.c

  1  #include"add.h"  
  2   
  3 int add(int a, int b)  
  4   
  5   return a+b;                                                                                                       
  6   

sub.h

  1 #pragma once   
  2   
  3 int sub(int x, int y);                                                                                                

sub.c

  1 #include"sub.h"  
  2   
  3 int sub(int x,int y)  
  4   
  5   return x - y;                                                                                                     
  6 

打包

我们将刚刚的4个文件先生成静态库

先让源文件生成对应的目标文件

2.使用ar -rc生成静态库

成功生成静态库
可以用命令:

ar - tv查看静态库的内容

3.将头文件和静态库组织起来

我们把自己的库给别人用,要给别人头文件和生成的库。我们把所有的头文件放在include下,把库放到mylib下。

我们还可以使用Makefile,非常的省事

一个make生成静态库

一个make output将头文件和静态库链接起来

使用

用main.c来测试一下

  1 #include<stdio.h>
  2 #include"add.h"
  3 
  4 int main()
  5 
  6   int a = 30;
  7   int b = 10;
  8   printf("a+b=%d\\n",a+b);                                                                                           
  9   return 0;
 10 

此时使用gcc需要带上3个选项
-I:指定头文件搜索路径
-L:库文件搜索路径
-l:指定链接哪个库,(有许多库的情况下)

我把其他文件都干掉,只留下mylib。

可以成功运行。

动态库的打包和使用

动态库跟上面的静态库基本是一样的步骤,只需要把Makefile改成动态链接。上面的add.c,add.h上面的博主在这里就不写了,跟静态库的代码是一样的。
我们直接到打包,将静态库的Makefile修改一下:

一个make就生成库

make output将头文件和库组织起来

使用

使用和静态库也是一样的,使用3选项
还是创建一个main.来测试一下,我把其他的文件都干掉只留库mylib

成功运行了。和静态库的使用是一样的,要多多练习。
本篇文章到这里就结束了。由于博主水平有限,如有错误,请直接练习博主,万分感谢!!!
欢迎一起交流!!!

以上是关于Linux文件系统,软硬连接,动静态库的主要内容,如果未能解决你的问题,请参考以下文章

Linux软硬链接和动静态库详解

Linux软硬链接和动静态库详解

理解Linux—inode

万字详解Linux系列文件系统动静态库

万字详解Linux系列文件系统动静态库

Linux动静态库打包