Linux操作系统学习(了解文件系统&&动静态库)

浅谈文件系统

当我们创建一个文件时由两部分组成:文件内容+文件属性,即使是空文件也有文件属性

一个文件没有被打开是存储在磁盘中的,而磁盘是计算机中的一个机械设备(SSD、FLASH等等)

以机械硬盘来举例

我们的数据都放在盘片上,磁头可以摆动,盘片不断在转动,这样磁头就可以定位到盘片上的特定位置。在盘片同心圆的一圈上有很多小段区域,称为扇区,它存储着数据,这一圈称为一个磁道,在同一圆心上的盘片的相同半径上的磁道合起来形成一个柱面。

磁盘写入的基本单位是扇区,一般一个扇区是512字节;磁盘和OS进行数据交互时的基本单位是4KB(具体和内存以及IO交互效率有关)

我们可以把磁盘想象成线性结构(如磁带那样)

可以把磁盘看成一个大数组,把扇区中的地址与数组建立起映射关系,并以LBA记录数组下标

若要与磁盘数据交互,需要把LBA转化成扇区地址

了解EXT系列文件系统

​ 一个磁盘是很大的,那就需要对其进行管理,可是直接管理整个磁盘是很费时费力的,例如一个老师管理一个年级,那可能连人名都记不全,所以为了方便管理,就把磁盘分区管理

例如我们电脑中的磁盘分区,所以要使用磁盘具体可以分为两步:

  • 把磁盘划分为小空间(磁盘分区)
  • 格式化,给分区写入文件系统

例如学校校长->各班班主任->班长->组长->学生,所以再分区的基础上 ,又细分为很多小块区域(block group)组成

站在OS角度,每个区文件系统都一样,只要能管理好一个区,就能管理好整个磁盘

下面就以一个Block group来理解这个文件系统

​ 在一个Block group中,Data blocks和indoe table中又分别由小块空间组成,每个小块空间又有自己的编号,文件内容存在Data block是中,文件属性存在indoe table中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ZD1gT7u-1677869190894)(G:\Typora\图片保存\image-20221209105606647.png)]

那属性怎么找到内容所在位置呢?

​ 首先我们需要知道的是,在Linux中文件名都是给用户使用的,实际的文件都有一个inode标号,而内部找到一个文件都是通过inode标号来找到具体文件的

​ inode table里面有很多数据块,每个数据块称之为一个 inode(有对应的 inode 编号),存放文件属性。

​ 每个inode table数据块中存在着一个struct inode记录着文件的所有属性信息和Data中 blocks所占的数据块的编号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ed8xrZu8-1677869190895)(G:\Typora\图片保存\image-20221209111257299.png)]

所以最终我们只要根据inode编号找到inode属性,根据inode属性找到对应的数据块就找到了整个文件

那么申请数据块时怎么知道哪个占用哪个没被占用?

​ 中途有删除也不可能像顺序表一样把整体数据挪动所以这里用位图来解决这个问题,Block bitmap和inode bitmap分别代表Blocks的占用情况和inode的占用情况

(位图这里就不介绍了)

一个bit位用0记录空,用1记录占用,只需要对bit位判断是0还是1就判断了 inode和blocks使用情况

block group总结:

  • Data blocks:由多数据块组成,每个数据块称之为一个 block,存放文件内容
  • inode Table:由很多数据块组成,每个数据块称之为一个 inode,存放文件属性。
  • inode Bitmap:记录inode数据块的占用情况
  • Block Bitmap:记录blocks数据块的占用情况
  • Group Descriptor Table:与 Block group 相关,描述这个组的相关信息。
  • Super Block:记录整个分区的使用情况,这么做可以预防因为磁盘部分损坏导致的数据丢失,假如整个分区只有一份Super Block,万一磁盘损坏的部分正好包括这部分,那等于整个磁盘的数据就丢失了,所以每个Block group都有可以降低数据丢失的风险

目录与inode的关系

​ 实际上目录也是文件,也有自己的数据块,目录数据块本质上是一张表,是inode编号与文件名的映射表,所以目录数据块存放的是文件名和inode的映射关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FjAWdxy6-1677869190895)(G:\Typora\图片保存\image-20221209120602650.png)]
(当前目录)

查看一个文件时的流程是什么?

cat temp.c

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VpIE28HO-1677869190895)(G:\Typora\图片保存\image-20221209120527849.png)]

先查看/home/awd/test6中 该文件名对应的映射inode编号 ->

通过inode编号查看inode table中的文件属性 ->

通过文件属性找到Data blocks存放的文件数据

那么删除一个文件的流程是什么呢?

rm temp.c

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mxrh4I62-1677869190896)(G:\Typora\图片保存\image-20221209121437947.png)]

先通过文件名在目录下找到对应的inode编号 ->

用inode编号 在block、inode的bitmap中把对应的映射位的1置0即可

​ 数据内容根本不用动,我们看到的剩余空间容量多少多少实际是,根据占用位置描述的,也就是系统让我们看到的只是描述的剩余多少多少空间占用多少多少空间,创建新的时候覆盖就可以了,之后再更新空间描述的使用情况。真要是清空数据也不利于效率,毕竟总容量就那么大,删除也不会真扩容。

当我们touch一个文件会发生什么?

touch temp.c

先在位图中查看 block和inode占用情况 ->

找到空位置写入(覆盖)自己的文件的属性和数据 ->

在当前目录记录inode编号与文件名的映射关系

​ 在我们windows中的回收站其实就相当于一个目录,只是把要删除的文件inode转移到回收站这个目录下建立映射关系,本质在磁盘中的位置并没有改变,而清空回收站才是删除(类似于把位图中的映射位置置空)

​ 剪切也同理,就是更改目录

软硬链接

先来看软连接的语法

ln -s log.txt los_s   创建

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4dd6s5b-1677869190896)(G:\Typora\图片保存\image-20221209125102410.png)]

unlink los_s          删除

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lin37wM9-1677869190896)(G:\Typora\图片保存\image-20221209141201916.png)]

当一个路径过长时,就可以使用软连接,类似于C++中的auto,或者windows中的快捷方式

软连接有独立的inode,是一个独立文件,有自己的inode属性和自己的数据块,数据块保存的是指向的路径+文件名

(例如C语言中指针指向的变量和指针变量他都是变量都有自己的地址)

硬链接语法

ln log.txt log

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xW0BY0nf-1677869190896)(G:\Typora\图片保存\image-20221209141028169.png)]

硬链接不是独立的文件,没有独立的inode号,而是一个别名(本质是根据原文件inode号,硬链接新的名字建立的映射关系)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0fAwI3cp-1677869190897)(G:\Typora\图片保存\image-20221209142233388.png)]

指的是有多少个文件名建立的映射关系,这个数字存在inode结构体中
也就是引用计数,有一个名字建立映射就++,删除一个就–

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FnrTYwuG-1677869190897)(G:\Typora\图片保存\image-20221209142637327.png)]

当我们查看目录时的 . .. 就是一种硬链接

  • .对应着当前所在目录,上图当前目录是test16文件中,所以与test16文件的inode号一样
  • .. 对应着当前目录的上一层目录,也就是test16的上层目录,就是awd,所以和awd的inode号一样

查看具体属性:

可以输入 stat + 文件名查看具体属性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kyCF13bg-1677869190897)(G:\Typora\图片保存\image-20221212083906930.png)]


动静态库

一般库分为两种:动态库和静态库

静态库:将所有源文件生成目标文件(.o),再通过 ar 工具将目标文件打包得到静态库文件

动态库:在生成.o文件时还需要添加额外参数 -fpic /-fPIC,打包时添加shared参数告诉编译器生成一个动态链接库

具体步骤下面介绍

在Linux:

  • 动态库以.so作为文件后缀
  • 静态库以.a作为文件后缀

库文件的命名:

  • 动态库:libxxxx.so
  • 静态库:lib.xxx.a

库真实的名字:去掉lib前缀,去掉后缀,剩下的就是库名称

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HyqxQIVW-1677869190897)(G:\Typora\图片保存\image-20221211101557248.png)]

gcc一般默认是动态链接编译,想要静态链接编译可以在编译时加 -static

静态编译链接

在这里插入图片描述

静态编译链接是把库中需要的的代码拷贝到可执行程序中,所以静态编译的文件一般比较大,因为包含了库文件

动态编译链接

ldd工具可以查看动态库依赖关系

如何制作库:

库本身是由二进制文件组成的,一般一套完整的库有一下三点:

  • 库文件本身(.o/.obj的合集)
  • 头文件.h
  • 说明文档

静态库:

  1. 把所有的源文件生成一份.o/.obj文件
  2. 把所有的.o/.obj文件打包成一个库文件,要根据上面介绍的命名规则
  3. 编译链接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y1ZPyBMf-1677869190898)(G:\Typora\图片保存\image-20221211113038800.png)]

  • ar -rc 静态库名称 .o文件名称命令的作用是把 .o 文件打包形成一个静态库。

使用静态库:

这里我把output剪切到上一目录改名为SRAM了

temp.c

#include "sub.h"			//#include "./file/output/sub.h"
#include "add.h"			//#include "./file/output/add.h"

int main()
{
  int x = 20;
  int y = 10;
  int ret1 = sub(x,y);
  int ret2 = add(x,y);

  printf("add:%d\n",ret2);
  printf("sub:%d\n",ret1);
  
  return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YBHD4v62-1677869190898)(G:\Typora\图片保存\image-20221211123418018.png)]

  • -I(大写i):指明头文件搜索路径
  • -L:指明库文件的搜索路径
  • -l(小写L):指明要连接哪一个库

​ 我们平时写的代码不用指明搜索路径是因为,这些库都放在默认路径下:/lib64,/usr/lib,/usr/include等。所以也可以把自己的库放到默认路径下(但不推荐)

动态库:

动态库的制作与静态库基本一致

​ 打包.o文件生成动态库,此时的库后缀应该是.so,但一些选项和静态的不一样:

  • gcc -shared -o 动态库名称 .o文件名称生成一个动态链接的共享库。
  • -fPIC:表示生成位置无关码。

使用动态库:

编译时指明路径和库名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R8PlAUOr-1677869190898)(G:\Typora\图片保存\image-20221211131131940.png)]

但是编译通过了,也生成可执行文件了,可是运行时就报错了,为什么呢?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dZW2wNOd-1677869190898)(G:\Typora\图片保存\image-20221211131248584.png)]

因为动态库不光编译连接时需要找到动态库,再运行时也需要找到动态库,所以我们要让他运行时也能找到库

做法

  • 利用环境变量 LD_LIBRARY_PATH

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ouFjeSqx-1677869190899)(G:\Typora\图片保存\image-20221211131555040.png)]

把库的路径放到环境变量中,但只限于本次会话

  • 把库加载到默认路径下(不建议)

动态库与静态库制作及使用的区别:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lr4CDcRE-1677869190899)(G:\Typora\图片保存\image-20221211131902408.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ui5Jdv98-1677869190899)(G:\Typora\图片保存\image-20221211132256020.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UMjR5tBh-1677869190899)(G:\Typora\图片保存\image-20221211132318458.png)]

创建时:注意后缀,ar -rc 、-shared -fPIC

使用时:动态库需要把库路径放到环境变量中

还要注意:指明文件路径和库的名称

制作库的步骤:

  • 把源文件生成.o文件

  • 把所有.o文件打包成库(根据动静态,选择后缀和选项)

  • 把库文件和所有头文件打包发布

  • 最后编译连接时注意动静态的区别和文件路径

注意:上面说的是动静态库,不是动静态的编译链接,gcc/g++默认是动态链接,静态链接需要手动添加 -static选项

本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。

Windows下是.obj文件,Linux下是.o文件

  • 静态库的特点:

    • 在程序编译的链接阶段,静态库的代码就被拷贝进了程序中,所以程序在运行时不需要找静态库。

    • 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。

    • 当静态库更新时,它所有的程序也需要更新,因为是和原来静态库的代码编译在一起的,很可能因为库中小改动导致改动整个程序(当库更新时,等于原库文件发生改变,而程序中拷贝的是原库的代码,所以需要重新编译链接)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CvVNpA59-1677869190899)(G:\Typora\图片保存\image-20221212083611058.png)]

  • 动态库的特点:

    • 相比于静态库的运行速度较快,程序在运行的时候才去链接动态库的代码,所以在运行时也需要找到动态库

    • 动态库(共享库)的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。

    • 对于更新发布时,不会像静态库那样从上到下全改动,一般只需要更新动态库即可(一般库的更新不会改变原有的逻辑与接口,只会是优化和新增功能,而动态库是在程序编译时才链接库,所以只需要更新库即可)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrLDntxH-1677869190900)(G:\Typora\图片保存\image-20221212083619754.png)]

用静态库分别去动态链接和静态链接都可以编译,但是动态库只能动态链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值