文件系统和动静态库

news2024/11/22 20:50:44

目录

再识文件属性

查看文件属性的原理

初识inode

了解磁盘

什么是磁盘

磁盘的结构

磁盘的存储结构

CHS寻址

磁盘的逻辑结构

使用LBA地址的意义

理解文件系统

页框和页帧

分治思想管理

Linux ext2文件系统

软硬链接

软链接

硬链接

文件的三个时间

动静态库

动静态库的基本原理

制作一个自己的静态库

生成静态库

使用静态库

制作一个自己的动态库

生成动态库

使用动态库

动静态库的加载


再识文件属性

查看文件属性的原理

ls -l读取存储在磁盘上的文件信息,然后显示出来:

 

初识inode

//输入指令查看文件属性
ls -li

//输入指令stat 文件名,看到更多信息

上述结果中有几个文件属性需要我们理解(inode、Links等)

需要解释清楚它们,我们就需要了解清楚文件系统。

了解磁盘

在了解文件系统前,我们先了解最常见的存储介质,磁盘。

什么是磁盘

        磁盘是计算机的主要存储介质,它可以存储大量二进制数据,并防止断电后数据丢失。早期,计算机中使用软盘,但现在普遍使用硬盘。与之相对应的便是内存,内存有掉电易失性

磁盘的结构

 

注意点:

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

  2. 每个盘面都有一个磁头。

  3. 磁头和盘面是没有接触的,为了防止抖动。

磁盘的存储结构

 

我们将盘面进行划分:

注意点:

  • 扇区的面积会不同,但都代表512byte空间,通过控制存储信息的密度

 

注意点:

  • 磁头是共进退的。

CHS寻址

那么磁盘是如何寻址的呢?

  • 磁盘寻址的单位是扇区(512byte)

 

  • 磁头来回摆动用来定位在哪个磁道

  • 确定磁道后,盘片旋转时,磁头定位扇区

如何在磁盘中定位任何一个扇区呢?

  1. 先定位在哪一个磁道(柱面(Cylinder))。

  2. 再定位盘面(即对应的磁头(Head))。

  3. 最后定位在哪一个扇区(Sector)。

磁盘中定位任何一个扇区,采用的硬件的基本定位方式:CHS定位法

磁盘的逻辑结构

磁盘在物理上是圆形的,我们能在逻辑上将其抽象为一个数组。

 

此时,我们只要知道扇区对应的下标就定位了该扇区。(操作系统中我们称这种地址为LBA地址

LBA如何转化为CHS呢?

假设:磁盘有4个盘面,每个盘面有10个磁道,每个磁道中划分了100个扇区,此时共有4000个扇区,每一个盘面有1000个扇区。

我们如何定位123号扇区在磁盘中的位置:

  1. 123/1000 = 0号盘面 H

  2. 123/100 = 1号磁道 C

  3. 123%100 = 23号扇区 S

通过这样的计算,我们就拿到了对应的CHS。

使用LBA地址的意义

  • 便于进行管理,我们只需要有对应的下标就行了。

  • 让操作系统的代码和具体硬件解耦,如果使用CHS,存储就和磁盘绑定在了一起,我们并不想强耦合。

理解文件系统

页框和页帧

虽然磁盘的访问的基本单位是512字节,但其依然很小,操作系统内的文件系统让我们同时对多个扇区进行读取,一般以1KB(两个扇区),2KB(4个扇区),4KB为基本单位。无论一次读取和修改多小的数据都会一次加载4KB空间到内存。这也就是我们所说的局部性原理。

注意点:

  • 内存被划分成了4KB大小的空间,即我们所说的页框

  • 磁盘中的文件按照4KB大小划分好的块,即我们所说的页帧

 

分治思想管理

我们的磁盘常用的大小是500GB,那么如何管理这500GB的空间呢?

我们要进行分区、分组两个步骤:

        此时,我们只需要先将一个组管理好,然后就能通过CV(复制粘贴该组的管理方法到其他组)管理好这个分区了,能管理好当前分区自然也能管理好其他分区,最终我们就管理好了整个磁盘。

Linux ext2文件系统

磁盘文件系统图(内核内存映像肯定有所不同):

磁盘是典型的块设

​        硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中**启动块(Boot Block)的大小是确定的**。

1. Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成.
2. 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。
3. GDT,Group Descriptor Table:块组描述符,描述块组属性信息
4. 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用。
5. inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
6. i节点表(inode Table):存放文件属性。 如 文件大小,所有者,最近修改时间等(除了文件名)。
7. 数据区(Data Blocks):存放文件内容。

注意点:

1. inode为了彼此区分,每一个inode都有一个自己的ID。
2. 一个文件一个inode。
3. 文件名并不在inode中存储。
4. 查找一个文件,统一使用的是inode编号(文件名和inode存在映射关系)。
5. Super Block在每个组中都有一份,如果Super Block的信息被破坏可以通过其余的备份来恢复。

接下来回答一些问题:

inode中是如何存储文件内容对应的Block的位置的?

假设inode的结构如下:

struct inode
{
    int id;
    mode_t mode;
    uid;
    size;
    //......
    int blocks[15];//存储的对应的Block的位置    
}

        其中有着一个blocks数组用来存储对应的文件内容所在的位置,此时也许你会好奇,就15个位置能存的下吗?答案是能。前13个位置与inode是一一对应,但下标为13和14的位置采用的是二级检索和三级检索。

 

下标13对应的Block中存放的是其余Block的位置。下标14的同理(再套一层)。

创建的目录文件中存储的是什么呢?

 

        我们可以看到,一个目录是有自己对应的inode的,那么目录文件内容中存储的是什么呢

答案是文件名和对应文件inode的映射关系

如何证明?

 

        一个目录内文件是否能删除取决于是否拥有对应的写权限!即我们需要取消对应文件名和inode的映射关系

为什么我们下载文件慢而删除文件快

我们都知道下载文件慢而删除文件快,其原理就在于:

  • 当我们下载文件时,首先我们要在inode位图中将对应的indoe由0置1,接着我们需要在数据区不断的申请Block,并将Block位图对应的位置由0置1,还需要在inode中存储其对应的位置。

  • 当我们删除文件时,很简单了,直接把inode位图和Block位图中对应的位置由1置0即可。

所以我们删除文件只是改掉了对应位图中的比特位,实际文件数据还是留在磁盘中的。

文件恢复是什么原理?

        系统日志中会存储删除掉的文件的inode,我们可以找到该inode,恢复其在inode位图中的位置,再通过inode找到文件对应的Block,恢复Block位图中对应的位置,由此,我们便成功恢复了文件。

所以我们误删文件想恢复时最好别瞎操作,避免对原有的数据进行了覆盖导致无法恢复。

软硬链接

软链接

ln -s 源文件所在路径 建立的链接文件名

 在上图中,我们建立了一个test的链接文件lktest,通过其,我们可以直接运行test.

ls -li //查看inode

 两者文件的inode不同,lktest是一个全新的文件,那么其内部存储的是什么呢?

        我们首先删除了test应用程序,我们发现软链接失效了,当我们再次在当前路径创建相同文件名的文件时,其又恢复了正常。由此观之,我们可以推断,其内部存储的是文件所在的路径

注意点:

  • 软链接文件大小很小,是因为其内部只是存储了文件的路径。

  • 我们可以将其看作为Windows的快捷方式

如何解除软链接?

unlink 文件名

 

硬链接

ln 文件所在路径 链接文件名

 我们创建了一个硬链接。

ls -li   //查看inode

 我们发现二者的inode竟然是相同的。并且其硬链接数变成了2.

删除test后,lktest依然能正常运行,硬连接数变为了1.

我们可以这样理解:

  • test和lktest的链接状态完全相同,他们被称为指向文件的硬链接。内核记录了这个连接数,inode 1054954 的硬连接数为2

  • 创建硬链接时,文件名lktest与文件test的inode建立了映射关系。

  • 我们在删除文件时干了两件事情:

    • 1.在目录中将对应的记录删除。

    • 2.将硬链接数-1,如果为0,则将对应的磁盘释放。

接着来看一个现象:

 为什么创建目录初始的硬链接数是2?

Test目录里的.文件也是硬链接。同理..是上一个目录的硬链接

操作系统不允许我们为目录创建硬链接

 

        Linux系统中,磁盘上的文件和目录被组成一棵目录树,每个节点都是目录或文件。如果我们自己在目录c中建立了目录a的硬链接,就可能会在搜索文件时造成死循环的问题。因此操作系统不让我们进行该操作。

文件的三个时间

通过stat指令查看文件的三个时间:

 

下面解释一下文件的三个时间:

  • Access 最后访问时间

  • Modify 文件内容最后修改时间

  • Change 属性最后修改时间

注意点:

  • Access时间一般不会立刻更新,因为文件的访问可能十分频繁,操作系统内有自己的更新策略。

  • Modify时间更改时Change时间往往也会一起变化,因为我们更改文件内容时实际上就造成了文件属性的变化,如文件大小等。

动静态库

动静态库的基本原理

程序编译的四个阶段

  1. 预处理(进行宏替换):预处理功能主要包括宏定义,文件包含,条件编译,去注释等。生成XXX.i的文件

  2. 编译(生成汇编):要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,把代码翻译成汇编语言。生成XXX.s的文件

  3. 汇编(生成机器可识别代码):汇编阶段是把编译阶段生成的“.s”文件转成目标文件。生成XXX.o文件

  4. 连接(生成可执行文件或库文件):在成功编译之后,就进入了链接阶段。生成可执行程序。

库的本质:.o文件的集合

#include "mul.h"
#include "sub.h"
int main()
{
    int a = 5;
    int b = 3;
    printf("a*b = %d\n",mul(a,b));
    printf("a-b = %d\n",sub(a,b));
    return 0;
}

动静态库实际上就是把我们编译出的.o文件(方法的实现)进行了打包。再给出对应的.h文件(对应的方法)。

封装动静态库的标准格式:

我们把自己的库给别人用的时候,实际上需要给别人两个文件夹:

  • 一个文件夹下面放的是一堆头文件的集合。

  • 另一个文件夹下面放的是所有的库文件。

mkdir -p mylib/include      
mkdir -p mylib/lib
cp -f *.a mylib/lib
cp -f *.h mylib/include

我们创建一个目录文件mylib,再在里面分别创建一个lib目录(放库文件),一个include目录(放头文件)。

我们发布自己的库时只需要发布打包压缩好的mylib就可以了。

制作一个自己的静态库

生成静态库

需要用到命令:

生成静态库

ar -rc libmymath.a mul.o sub.o
  • ar(archive)是gnu归档工具,rc表示(replace and create)

 查看静态库中的目录列表

ar -tv libmymath.a

  • t:列出静态库中的文件

  • v:verbose 详细信息

进行打包:

mkdir -p mylib/include     
mkdir -p mylib/lib
cp -f *.a mylib/lib
cp -f *.h mylib/include

使用静态库

gcc -o main main.c -I./mylib/include -L./mylib/lib -lmymath

使用自己制作的库,我们编译时需要增加三个选项:

  1. -I:指定头文件所在的路径。

  2. -L:指定库文件所在的路径。

  3. -l: 指明使用的库的名称。

注意点:

  • 编译器并不清楚我们的头文件在哪里,其只会在当前路径和系统路径下寻找,因此我们需要添加路径。

  • 库文件同上。

  • 库的名称是什么?我们去掉前缀lib和后缀.a或者.so及其后面的版本号,就是库的名称。之所以要指定库的名称,是因为lib目录下可能有大量的库文件。

  • 上面的三个选项后可加空格,并不影响。

运行成功

使用自制的库每次编译都要带上这一串指令,显得十分繁琐,有何方法能简化呢?

把库文件和头文件拷贝到系统路径下

sudo cp mylib/include/*.h /usr/include
sudo cp mylib/lib/*.a /usr/lib64

我们把库文件和头文件拷贝到系统路径下的过程实际上就是安装了这个库

我们把库安装好后编译时还是需要指明库的名称,这也是为什么我们使用第三方库时总需要指明库名称的原因。

提示:我们并不推荐将自己写的库放进系统路径,因为我们的库并没有很好的经过验证,会对系统文件造成污染。

一个现象:

我们发现用自己的静态库编译的可执行程序居然显示是动态链接的。为什么?

  • 因为形成一个可执行程序,往往不会仅仅依赖一个库,我们的程序当然还依赖了c语言库。

  • gcc默认是动态链接的(建议行为)。

使用Makefile进行打包

我们可以用Makefile进行打包,方便我们后续的使用

libmymath.a: mul.o sub.o  //生成库
	ar -rc $@ $^
mul.o: mul.c
	gcc -c -o $@ $^
sub.o: sub.c
	gcc -c -o $@ $^

.PHONY:output       //包装库
output:
	mkdir -p mylib/include     
	mkdir -p mylib/lib
	cp -f *.a mylib/lib
	cp -f *.h mylib/include

.PHONY:clean   //删除
clean:
	rm -rf *.o libmymath.a mylib

我们就可以很轻松的进行操作了。

制作一个自己的动态库

生成动态库

生产动态库我们需要进行两步操作:

  1. //编译时添加fPIC选项
    gcc -fPIC -c -o mul.o mul.c
    gcc -fPIC -c -o sub.o sub.c
  2. gcc -shared -o libmymath.so *.o

注意点:

  • shared: 表示生成共享库格式

  • fPIC:产生位置无关码(position independent code) (让动态库中的指定函数的地址是偏移地址,相对编址方式)

  • 库名规则:libxxx.so

使用Makefile进行打包

 

libmymath.so: mul.o sub.o  //生成库
	gcc -shared -o $@ $^
mul.o: mul.c
	gcc -fPIC -c -o $@ $^
sub.o: sub.c
	gcc -fPIC -c -o $@ $^

.PHONY:output       //包装库
output:
	mkdir -p mylib/include     
	mkdir -p mylib/lib
	cp -f *.so mylib/lib
	cp -f *.h mylib/include

.PHONY:clean   //删除
clean:
	rm -rf *.o libmymath.so mylib

使用动态库

与静态库时的使用相同

gcc -o main main.c -I./mylib/include -L./mylib/lib -lmymath

但我们发现我们编译出的可执行程序无法运行,为何?

        我们使用-I-L-l这三个选项都是在编译期间告诉编译器我们使用的头文件和库文件在哪里,但是可执行程序生成后就与编译器没有关系了,操作系统运行可执行程序时可不知道动态库在哪里

我们通过ldd命令可以查看到:

我们一般有四种方法解决该问题:

  • 拷贝.so文件到系统共享库路径下, 一般指/usr/lib64。

  •   更改 LD_LIBRARY_PATH。

LD_LIBRARY_PATH是环境变量,里面存储了运行动态查找库时所要搜索的路径。

我们使用export指令将我们库的路径导入其中即可

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:所在的路径

但此种方法在重启shell后环境变量会重置而失效(环境变量的配置文件)。

  • 配置/etc/ld.so.conf.d/

        我们可以看到该目录下都是后缀为.conf的配置文件,这些配置文件当中存放的都是路径。我们只需要用库文件的路径生成.conf的文件,然后拷贝到该目录下即可。拷贝后需要使用ldconfig指令更新配置后才会生效。

  • 在当前目录创建软连接

 我们可以在当前路径下建立一个与库文件同名的软连接,查找动态库时会默认在当前路径查找。

动静态库的加载

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库

  • 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码

  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。

  • 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)。

  • 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/457430.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java运行python脚本,待完善版

参考资料: windows下调用CMD运行方式 兼容linux/windows,同步异步方式 指定特殊运行环境的运行(如:anaconda运行环境) 整合以上三种方式终极版源码 相关内容: 调用python脚本传参说明 如果不传参数,python脚本可以随意写,比如:

【课程介绍篇】C/C++后台开发岗位技能知识树

1 C/C后台开发岗位技能知识树 2 Linux C/C后台架构开发 成长体系课程 3 C技术历史更新 https://www.0voice.com/uiwebsite/html/courses/

《UVM实战》学习笔记——第七章 UVM中的寄存器模型2——期望值/镜像值、自动/显示预测、操作方式

文章目录 前言一、寄存器模型对DUT的模拟1.1 期望值和镜像值1.2 常见操作对期望值和镜像值的影响 二、prediction分类2.1 自动预测2.2 显式预测 三、访问寄存器方式四、mem和reg的联系和差别五、内建built_in sequence5.1 寄存器模型内建序列5.2 存储器模型内建序列5.3 禁止域名…

安装APP时弹窗未知风险未知开发者,还能下载吗?

随着移动互联网的不断普及,人们的日常生活已与手机密不可分。根据相关研究,在使用手机时,人们90%以上的时间都花在某些应用程序上,巨大的需求使得各种各样的APP被开发出来。然而人们在使用APP时必须更加注意其是否来源可信企业&am…

数据结构与算法基础-学习-21-查找之平衡二叉树(AVL树)

目录 一、个人理解 二、最小失衡子树 三、平衡调整的四种类型 1、LL型 2、RR型 3、LR型 4、RL型 四、如何平衡调整 1、LL型调整 2、LR型调整 五、宏定义 六、结构体类型定义 1、AVL树结点类型 2、AVL树类型 3、AVL树结点搜索路径类型 七、函数定义 1、初始化AV…

基于CMS项目的JDBC的实战

基于CMS项目的JDBC的实战 使用的Javase技术,进行控制台输出的客户管理系统(CMS),主要功能包含登录,注册、客户信息的展示,客户信息的更新,客户信息添加删除客户、退出系统。 设计创建数据库 …

PEX高效批量网络装机

目录 一、部署PXE远程安装服务 1)PXE概述 若要搭建PEX网络体系,必须满足以下几个前提条件 2)搭建PXE远程安装服务器 ①安装并启用 TFTP 服务 ②安装并启用 DHCP 服务 ​编辑 ③准备 Linux 内核、初始化镜像文件 ④准备 PXE 引导程序 …

CUDA下载与对应版本查询

文章目录 1 算力,CUDA Driver Version,CUDA Runtime Version2 显卡型号3 实操4 镜像 1 算力,CUDA Driver Version,CUDA Runtime Version 比如说我们进入pytorch官网中,点击下载,如何找到适合自己的CUDA版本…

SCAU 统计学 实验5

8.14 总体平均值(μ):7.0 cm 总体方差(σ):0.03 cm 样本平均值(x̄):6.97 cm 样本方差(s):0.0375 cm 样本大小(n&#xff…

复旦MOSS大模型开源了!Github和Hugging Face同时上线

来源:量子位 复旦大模型MOSS,正式开源了! 作为国内首个开放测试的类ChatGPT产品,MOSS开源地址一放出,又冲上知乎热搜: 从官网介绍来看,MOSS是一个拥有160亿参数的开源对话语言模型。 它由约7…

EventLog Analyzer:高效保护网络安全的强大工具

网络安全是当今数字化世界中最为重要的话题之一。随着越来越多的组织、企业和个人将其业务转移到互联网上,网络安全问题变得越来越严峻。针对这个问题,EventLog Analyzer提供了一个有效的解决方案,让网络管理员可以更好地监控和保护其网络环境…

【虚拟仿真】Unity3D中实现UI的单击、双击、按压、拖动的不同状态判断

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 之前写了一篇在Unity中鼠标的单击、双击、拖动的文章&#xff…

Improving Language Understanding by Generative Pre-Training 论文阅读

论文题目:通过生成式预训练提高语言理解能力 GPT的全称:Generative Pre-trained Transformer。 Generative是指GPT可以利用先前的输入文本来生成新的文本。GPT的生成过程是基于统计的,它可以预测输入序列的下一个单词或字符,从而生…

春招,进阿里了....

个人背景是东北某 985 科班本硕,做的 测试开发,有两个自己写的小项目。下面是一些印象比较深刻的面试题 阿里一面 什么是软件测试? 软件测试过程中会面向哪些群体? 开发一个软件都要经过哪些阶段? 什么是黑盒测试&…

一块钱看Android Debug: avc denied 已存在的目录不能访问

某三方应用,使用了USB摄像头,启动应用后功能不能使用,看log有如下错误, denied后面{}里的是要执行的动作,比如append,open,execmod,link等等 scontext指的是域,对应的是te文件 上面报错这条对应te文件是untrusted_app.te, scontex…

如何将 WhatsApp 聊天添加到您的网站

WhatsApp是全球最受欢迎的消息传递应用程序。平台上有超过 2 亿活跃用户与朋友、家人和企业进行交流。对于企业而言,WhatsApp 是与客户进行个人、可访问和非正式对话的理想渠道。 要将 WhatsApp 作为渠道引入您的客户旅程,第一步是将 WhatsApp 聊天按钮…

2023软件测试工具大全(自动化、接口、性能、安全、测试管理)

目录 前言 一、自动化测试工具 Selenium Appium TestComplete 二、接口测试工具 Postman SoapUI JMeter 三、性能测试工具 LoadRunner JMeter Gatling 四、安全测试工具 Burp Suite OWASP ZAP Nmap 五、测试管理工具 TestRail JIRA TestLink 总结 前言 …

【JavaScript】this理解总结

概念 this是函数运行时所在的对象。 使用场合 1.全局环境 全局环境使用this,this指向顶层对象。 2.构造函数 构造函数体里面的this,this指向是构造出来的实例对象。 3.对象的方法 ● 如果对象的方法里面包含this,this的指向就是方法运…

ASPICE详细介绍-4.车载项目为什么要符合ASPICE标准?

目录 车载项目为什么要符合ASPICE标准?ASPICE与功能安全的关系、区别?各大车厂对软件体系的要求 车载项目为什么要符合ASPICE标准? ASPICE(Automotive Software Process Improvement and Capability Determination)最…

sacrebleu找不到报错(无法直接下载)

网络问题无法下载,下载下来py文件,放到同级目录下面 https://raw.githubusercontent.com/huggingface/datasets/2.11.0/metrics/sacrebleu/sacrebleu.py然后注释掉版本报错