Linux —— 文件系统概述、软硬链接与动静态库

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

1.文件系统概述

1.1磁盘的基本存储结构

 1.2磁盘的基本逻辑结构

1.3操作系统中的文件系统

 1.4文件系统如何对磁盘进行管理

2.软链接、硬链接

2.1软链接

2.2硬链接

2.3目录的硬链接数

3.静态库和动态库

3.1静态库的制作

3.2静态库的使用

3.3动态库的制作

3.4动态库的使用

 3.5动静态库的加载方式

1.文件系统概述

1.1磁盘的基本存储结构

磁盘是一个机械结构构成的外设所以访问的速度相对于CPU来说会显得非常慢。

一个磁盘由多个盘片(每个盘片对应多个盘面)和多个磁头(每个盘面对应一个磁头)构成(基本结构)。每一个盘面有很多的同心圆这些圆圈就是磁道。磁盘寻址的基本单位为扇区(512字节)所以磁盘又被称为块设备文件。每一个磁道的某一段对应一个扇区(即使磁道的周长各不相同但是数据量却一样)。 

 1.2磁盘的基本逻辑结构

磁盘的物理存储结构并不是线性的对其进行管理的成本会增加。为了方便我们把它逻辑抽象为线性结构。

只要知道了扇区的下标就可以看做成定位了一个扇区。这样的下标操作系统成为逻辑块地址(LBA地址)。 

进行逻辑抽象的原因有两个

1.便于管理。因为对线性数据结构的管理成本比对非线性数据结构管理的成本低。

2.不想让OS(操作系统)的代码和硬件强耦合。如果没有对磁盘进行逻辑抽象那么OS的代码可能是只针对磁盘进行管理但此时将磁盘替换为固态硬盘那么OS将无法管理固态硬盘。

1.3操作系统中的文件系统

即使磁盘是以扇区(512字节)为IO的基本单位但是操作系统仍然觉得这样不合适(512字节对于操作系统来说太小了而且会增加IO次数)。所以OS内的文件系统定制了一套IO方法每次进行IO时一次性读取多个扇区可能一次性读取两个扇区(1kb)也可能读取4个扇区(2kb)主流的一般都是读取8个扇区(4kb)。这样做的原因是为了提高IO效率和局部性原理。

所以此时得出两个结论

1.操作系统以4kb为单位管理内存称为页框。

2.磁盘文件以4kb为基本单位分块(特别是可执行文件)称为页帧。

 1.4文件系统如何对磁盘进行管理

 即使把磁盘逻辑抽象成了线性结构但是直接进行管理的成本还是太高。所以文件系统使用分治思想对磁盘进行管理即分区、分组管理。

 文件系统对每个分组进行管理。然后将每个分组的管理模式拷贝给其他分组这样就形成了对分区的管理。最后将每个分区的管理模式拷贝给其他分区这样就形成对整个磁盘的管理。

在Linux操作系统中文件=内容+属性所以Linux在管理文件时其内容和属性是分批存储的。每一个文件对应一个inode每一个inode是一个固定大小(128kb或者256kb)每一个inode存储了文件几乎所有的属性(除了文件名)inode为了区分彼此每一个inode都有一个对应的id([ls -li]查看)。内容是使用data blocks(数据块)存储的数据块的大小随着应用类型的变化也在变化。

可以看到上图绘制的分组结构现在来进行解释每一个区域的工作是什么

  • inode table保存了分组内部的所有(已用和未用)的inode。
  • data blocks保存了分组内部所有(已用和未用)的数据块。
  • inode bitmap分组内部inode对应的位图(比特位为1为已用0为未用比特位与当前文件的inode的位置对应第n个比特位对应第n个inode)。
  • block bitmap数据块对应的位图结构。
  • GDT(块组描述符表)存储对应分组的宏观数据(有多少个inode、数据块有多少可用或未用inode、数据块)。

在进行文件的查找时统一使用inode编号(可以跨组访问但不能跨分区一个分区对应一套文件系统)。每一个inode都有一个data block blocks数组存储数据块的编号其默认大小为15。下标为0~12都是一级索引(一个编号对应一个数据块)下标13~14分别是二级索引和三级索引。二、三级索引和一级索引的区别就在于一级索引的编号对应一个数据块二级索引的编号对应一个存储其他数据块编号的数据块三级索引以此类推。 

删除文件时不需要将文件的数据直接清楚掉而是只要把inode bitmap的比特位由1置0即可(让操作系统认为这个inode无人使用)。所以文件被删除时其数据还是存在的(是可恢复的)所以误删文件之后什么也不要做 

为什么我们在自己操作文件时并未使用inode编号而是直接操作文件名其原因在于我们的文件都是保存在目录下面的目录也是一个文件(所以目录有其对应的inode)其data block存储所有文件的文件名和inode的映射关系所以我们操作文件时使用的是文件名而不是inode。也就是说我们只需要知道文件名操作系统就会帮我们找到其对应的inode(所以同一目录下不能存在同名文件)。

2.软链接、硬链接

2.1软链接

使用如下命令为某一个文件建立软链接

ln -s 文件名(默认为当前路径) 软链接名称

软链接有一个独立的inode说明创建软链接即创建了一个新的文件。这个文件保存被链接文件的路径。所以其作用相当于Windows下的快捷方式。

2.2硬链接

使用如下命令为某一个文件建立硬链接

ln 文件名(默认为当前路径) 硬链接名称

硬链接没有独立的inode说明创建硬链接时没有创建新文件。硬链接的本质就是新增一个文件名和inode映射关系。

软硬链接的本质区别就是有无独立的inode

 所以对硬链接的修改也是对原文件的修改(类似于C++的引用)。

注意使用[ll -i]这个命令时权限与拥有者之间的数字这个数字便是硬链接数。删除文件时并不是直接销毁这个文件而是将其硬连接数减1当硬链接数为0时文件才被删除。 

2.3目录的硬链接数

让我们创建一个空目录时其默认硬链接数为2。

因为目录本身是一个文件占用一个硬链接数而目录下有一个隐藏的.目录这个.目录指的是当前目录所以又占用一个硬链接数。

 Linux不允许普通用户为目录建立硬链接其原因在于硬链接目录时需要将被链接目录下的所有数据都建立硬链接关系所以这是一项相当大的工程Linux不允许我们这么做。而能够为目录建立软链接是因为目录本身就是一个文件软连接只需要保存目录所在的位置就行了。

3.静态库和动态库

在C++编程时使用STL就是在使用C++给我们提供的库。如果某一天我们想要给其他人提供我们自己写的库了解静态库和动态库是非常有必要的。

前面的文章感性介绍了静态链接和动态链接。静态链接直接将方法拷贝至程序中这样使得访问速度快但是空间占用率高动态链接需要编译器主动去程序外部寻找方法这样使得访问速度慢但是空间占用率低。

库的思想无非就是将自己的目标文件(如果不想给他人透露我们的具体实现细节)和头文件提供给库的使用者。但是这样的作法是简单、直接并且暴力的。效率更高的做法便是将我们自己所有的.o文件(目标文件)打包成库文件配合头文件提供给使用者而打包工具和打包方式的不同决定了库文件是静态库还是动态库。

3.1静态库的制作

我们实现两个头文件my_add.h和my_sub.h实现两个源文件my_add.c和my_sub.c。代码编写完成后编写makefile将其目标文件和头文件放入一个文件夹当中。注意库文件的昵称格式一定要有前缀lib和后缀.a(静态库)或.so(动态库)

生成静态库需要使用如下命名

ar -rc lib*.a *.o...

//my_add.h
#pragma once
#include <stdio.h>
int add(int x,int y);
//my_add.c
#include "my_add.h"

int add(int x,int y)
{
    printf("%d + %d = %d\n",x,y,x+y);
    return x+y;
}
//my_sub.h
#pragma once
#include <stdio.h>
int sub(int x,int y);
//my_sub.c
#include "my_sub.h"

int sub(int x,int y)
{
    printf("%d - %d = %d",x,y,x-y);
    return x-y;
}
//makefile
libmystatic.a:my_add.o my_sub.o		#静态库需要依赖目标文件
	ar -rc $@ $^
my_add.o:my_add.c
	gcc -c my_add.c -o my_add.o
my_sub.o:my_sub.c
	gcc -c my_sub.c -o my_sub.o

.PHONY:output
output:
	mkdir -p mystaticlib/include	
	mkdir -p mystaticlib/lib
	cp -f *.h mystaticlib/include
	cp -f *.a mystaticlib/lib

.PHONY:clean
clean:
	rm -rf *.o libmystatic.a mystaticlib

箭头所指就是我们制作好的库了。我们可以使用压缩工具将其放在yum上供人下载也可以直接将此文件夹发给需要使用此库的使用者。

3.2静态库的使用

当使用者拿到制作好的库时可以有两种方法使用。一是将此文件夹里面的头文件拷贝至/usr/include路径下(系统存储头文件的目录)再将此文件夹里面的库文件拷贝至/lib64路径下(系统存储库文件的目录)此过程也称为安装库二是在编译自己写的程序时指明头文件、库文件的搜索路径。

主要介绍第二种方法这里站在使用者的角度来编写一份代码

//main.c
#include "my_add.h"
#include "my_sub.h"
#include <stdio.h>

int main()
{
    int ret1 = add(3,5);
    int ret2 = sub(7,4);
    return 0;
}

然后我们使用如下命令进行编译

gcc main.c -o mytest -I(大写的i) ./mystaticlib/include -L ./mystaticlib/lib -l(小写的L) mystatic

 现在解释命令各选项的作用

  • -I(大写的i)指定头文件的搜索路径。
  • -L指定库文件的搜索路径。
  • -l(小写的L)指定库文件昵称(去掉前缀和后缀就是库文件的昵称)。

那么对于第一种方法各位朋友可以自己去尝试。只不过在编译的时候需要指定库文件昵称因为对于gcc/g++这两款编译器来说只能认识自己的库。 

3.3动态库的制作

动态库的生成也需要目标文件但是生成目标文件时需要多加一个选项(产生与位置无关码)。

产生与位置无关码的目标文件的命令

gcc -fPIC -c *.c -o *.o

生成动态库的命令

gcc -shared -o lib*.so  *.o...

makefile可以这样编写 

//makefile
libmydynamic.so:my_add.o my_sub.o		
###生成动态库(使用gcc编译多加一个-shared选项阻止生成可执行文件)
	gcc -shared -o libmydynamic.so my_add.o my_sub.o	

###生成目标文件(使用gcc编译多加一个-fPIC选项生成与位置无关码)
my_add.o:my_add.c
	gcc -fPIC -c my_add.c -o my_add.o
my_sub.o:my_sub.c
	gcc -fPIC -c my_sub.c -o my_sub.o

.PHONY:output
output:
	mkdir -p mydynamiclib/include	
	mkdir -p mydynamiclib/lib
	cp -f *.h mydynamiclib/include
	cp -f *.so mydynamiclib/lib

.PHONY:clean
clean:
	rm -rf *.o libmydynamic.so mydynamiclib

 箭头所指就是我们制作好的库了。我们可以使用压缩工具将其放在yum上供人下载也可以直接将此文件夹发给需要使用此库的使用者。

3.4动态库的使用

与静态库的使用一样(一样使用main.c文件的代码为例)使用gcc生成可执行文件时操作一样。但是会发现生成的可执行文件运行不了。其原因在于使用的是动态库可执行文件内部就没有动态库的拷贝所以我们必须让OS和bash知道动态库在哪里

让OS和bash知道动态库在哪里有四种做法第一种将动态库的路径写入LD_LIBRARY_PATH的环境变量中这种方法的弊端是重启时失效(因为环境变量每次登录时自动配置)第二种与静态库一样将制作好的库的头文件、库文件暴力安装至系统目录下第三种在/etc/ld.so.conf.d/目录下自定义创建一个后缀为.conf的文件里面写入动态库的存储路径然后使用ldconfig命令更新配置第四种在系统路径下(/lib64)创建自己制作的动态库的软链接。

第一种方法演示 

第三种方法演示

 第四种方法演示

 3.5动静态库的加载方式

静态库直接加载到程序的代码区(直接将静态库拷贝至程序里)加载到内存后形成进程地址空间当cpu要处理调用静态库实现的方法的指令时操作系统只能通过地址空间的代码区再通过页表映射到物理内存的代码区。

 静态库的加载是一种绝对编址方式。因为程序里面包含有静态库所以静态库在程序当中一定有绝对的地址。所以静态链接对内存空间占用极高(当有100个不同的程序都使用了同一个静态库并加载到内存中那么内存当中就会有100份这个静态库)。

动态库的加载比较复杂它是一种相对编址方式。因为编译生成可执行文件时没有将动态库拷贝至程序里所以动态库的地址就不确定。那么程序的代码区存储的便是动态库的具体实现方法(函数)相对于动态库起始地址的偏移地址(假设动态库的起始地址为100函数的地址为120那么代码区存储的就是20)动态库的起始地址在动态库加载到内存时才能确定(操作系统有办法计算出动态库未加载到内存时函数的偏移地址)。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: linux

“Linux —— 文件系统概述、软硬链接与动静态库” 的相关文章