[Linux]理解文件系统!动静态库详细制作使用!(缓冲区、inode、软硬链接、动静态库)

        hello,大家好,这里是bang___bang_,今天来谈谈的文件系统知识,包含有缓冲区、inode、软硬链接、动静态库。本篇旨在分享记录知识,如有需要,希望能有所帮助。

目录

1️⃣缓冲区

🍙缓冲区的意义

🍙常见缓冲区刷新策略

🍙缓冲区位置猜想

🍥现象猜测

🍥现象解释

🍙用户级缓冲区位置

2️⃣理解文件系统

🍙磁盘的存储结构

🍥磁盘物理结构

🍥磁盘抽象结构

🍙文件系统

🍥inode vs 文件名

3️⃣软硬链接

🍙软链接

🍙硬链接

4️⃣动态库和静态库

🍙静态库

🍥生成静态库

🍥使用静态库

🍙动态库

🍥生成动态库

🍥使用动态库

🍙同时存在使用静态库还是动态库?

🍙特点总结

🍥静态库特点

🍥动态库特点


1️⃣缓冲区

问题:什么是缓冲区?

答:就是一段内存空间!!

🍙缓冲区的意义

我们知道了一段内存空间就是缓冲区,那么为什么要有缓冲区呢?

🌰生活例子映射:

        你在西安,你有个好朋友在上海,下个月好朋友要过生日了,你想送他一本你自己手绘的图画,你可以选择自己骑车亲手送给你的朋友;也可以选择下楼到顺丰选择寄送包裹然后回家。

毫无疑问:你自己骑车亲手送需要花费大量的时间,而你选择去顺丰寄包裹却很快,但是寄包裹也不是立马就会发送包裹,可能要等仓库堆满一批货物再一起发送。(图画是数据,顺丰是缓冲区)

自己骑车亲手送就相当于写透模式(WT)

而去顺丰寄包裹再可以直接回家就相当于写回模式(WB)

写透模式:直接将数据写到外部设备。

写回模式:先将数据写到缓冲区,当缓冲区的数据达到一定量时,再集中写到外部设备。

通过这个例子很显然能感受到缓冲区存在的意义了!

缓冲区存的意义:提高整机效率。主要是为了提高用户的响应速度!

🍙常见缓冲区刷新策略

缓冲策略=一般+特殊 

一般情况: 

        立即刷新

        行刷新(行缓冲)

        满刷新(全缓冲)

特殊情况:

        用户强制刷新(fflush)   

        进程退出   

一般而言:行缓冲的设备文件——显示器              全缓冲的设备文件——磁盘文件

        所有的设备,永远都倾向于全缓冲!

——缓冲区满了,才刷新—>更少次的IO操作—>更少次的外设的访问(提高效率)    

        和外部设备IO的时候,数据量的大小不是主要矛盾,和外设预备IO的过程是最耗费时间的!!

🍙缓冲区位置猜想

🍥现象猜测

🌰下面有一段代码,我们分别输出到显示屏,输出重定向到文件。

int main() {//C语言提供的printf("hello printf\n");fprintf(stdout, "hello fprintf\n");const char* s = "hello fputs\n";fputs(s, stdout);//OS提供的const char* ss = "hello write\n";write(1, ss, strlen(ss));fork();return 0;
}
现象图

        我们可以看到同一份代码,输出的结果却不一样,C的IO接口打印了2次,系统接口只打印1次和向显示器打印一样!也就是说子进程中有父进程C的IO接口对应的打印数据,但没有系统接口的。也就是说如果有缓冲区,那么绝对是C标准库来提供的

🍥现象解释

        ★如果向显示器打印,刷新策略是行刷新,那么进程执行到fork()函数时会将C标准库里缓冲区的数据全部进行刷新出去(fork无意义!)

        对于进程来说,当我们调用C文件接口fputs时,实际是将进程数据写入到C标准库中的缓冲区里,然后再统一调用系统接口write函数写入到对应的目标文件中。 

        如果我们进行输出重定向时,将原本写入到stdout文件中的数据写入到了磁盘文件中,缓冲模式就由行刷新变成了全缓冲。(\n便没有意义了!)当进程执行到代码fork()时,此时进程写入C标准库中的缓冲区数据还未刷新。当进程执行fork函数,便又生成了子进程。

        fork后父子进程退出:刷新数据到磁盘文件中,但是刷新实际上也是一次写入,因为进程的独立性,发生写时拷贝,打印2份!!

        ★缓冲区里的数据也是父进程的数据!提前强制刷新后,没有数据了,子进程也就没拷贝了!

🍙用户级缓冲区位置

问题:为什么fflush只传了stdout,却能找到缓冲区?

答:C语言中,打开文件,FILE* fopen(),struct FILE 结构体 内部封装了fd,还包含了该文件fd对应的语言层的缓冲区结构!

2️⃣理解文件系统

🌰我们使用ls -l指令读取文件信息,实际上是对磁盘中的文件进行读取。

磁盘——永久性存储介质(还有SSD,U盘,flash卡,光盘,磁带) 

磁盘是一个外设+还是我们计算机中唯一的一个机械设备!也就是说速度很慢!(相对于CPU)

🍙磁盘的存储结构

🍥磁盘物理结构

磁盘盘片,磁头,伺服系统,音圈马达等等

向磁盘写入,本质就是改变磁盘上的正负性。

磁盘的盘面被划分为一个个磁道,而磁道又被划分为一个个扇区。

扇区(磁道划分区域)是磁盘存储数据的基本单位(512byte)

如何将数据写入指定的一个扇区?有以下步骤:CHS寻址

    ——1.在哪一个面上(对应的就是哪一个磁头)

    ——2.在哪一个磁道(柱面)上

    ——3.在哪一个扇区上

如果我们有了CHS寻址方式,就可以找到任意一个扇区。

🍥磁盘抽象结构

小时候我们都有过磁带这种东西,他是缠在一起成圈的,但是我们也可以将他全拉出来成线状。磁盘我们也可以抽象成拉长后变为线状结构。

结构:圆形结构(CHS)->线性结构(LBA)

LBA是非常单纯的一种寻址模式﹔从0开始编号来定位扇区,第一扇区LBA=0,第二扇区LBA=1,依此类推。所以将来我们想要访问磁盘的某个扇区,只需要将通过LBA寻址后转换为CHS物理寻址。

最终:对磁盘的管理就变成了对一个个小分区的管理。 

🍙文件系统

磁盘文件系统图
上图为磁盘文件系统图(内核内存映像肯定有所不同), 磁盘是典型的块设备 ,硬盘分区被
划分为一个个的 block 。一个 block 的大小是由格式化的时候确定的,并且不可以更改。

虽然磁盘的基本单位是扇区(512字节),但是OS(文件系统)和磁盘进行IO的基本单位是:4KB(8*512byte)4KB->block大小

        ★Super Block->文件系统的属性信息

        ★Data bolcks->多个4KB大小的集合,保存的都是特定文件的内容

        ★inode Table:inode是一个大小为128字节的空间,保存的是对应文件的属性该块组内,所有文件的inode空间的集合,需要标识唯一性,每一个inode块,都要有一个inode编号!

        ★Block Bitmap:假设有10000+blocks,10000+比特位;比特位合特定的block是一一对应的,其中比特位为1,代表该block被占用,否则表示可用!

        ★inode Bitmap:假设有10000+个inode节点,就有10000+个比特位,比特位和特定的inode是一一对应的。其中bitmap中比特位为1,代表该inode被占用,否则表示可用!

        ★GDT:块组描述符,这个块组多大,已经使用了多少了,有多少个inode,已经占用了多少个,还剩多少,一共有多少个block,使用了多少....

我们将块组分割成上面的内容,并且写入相关的管理数据->每一个块组都这么干->整个分区就被写入了文件系统信息!!!(格式化)

🍥inode vs 文件名

  • 一个目录下,可以保存很多文件,但是这些文件都不会重名。
  • 目录是文件,目录有自己的inode和Data block

        文件名在目录的Data block 中,它保存着与inode编号的映射关系,文件名与inode互为key值,都是唯一的。

🌰为什么目录需要w权限?

因为在目录下创建文件时,这个目录有自己的数据块,我们创建文件的文件名就在目录的Data block 中,所以我们要将文件名和inode编号写入保存,此时必须需要w权限。

🌰为什么目录中具有r权限?

当我们需要显示文件名时,我们只能从目录的内容中获取文件名及相关属性,就必须访问目录的文件内容,就必须需要r权限从目录的Data block中获取文件名。 

🌰创建文件,系统做了什么?

特定分组找到没有使用的inode,分配inode编号,如果文件有内容,向文件内容当中申请Data Block,设置Block Bitmap,建立inode和Bitmap的映射,inode和Bitmap、Data Block的对应关系并写到inode结点中,inode文件名对应的映射关系写到特定的目录的DataBlock中。

🌰删除文件,系统做了什么?

删除文件肯定是在这个目录下删除,找到这个目录的Data Block, 删文件用户提供文件名,在Data Block中索引查询由文件名进行映射的inode编号,找到将inodeBitmap对应的比特位由1置为0,将Block Bitmap中的比特位由1置为0,在目录的Data Blocks中将文件名与inode编号解除映射关系。

🌰查看文件,系统做了什么?

根据文件名找到inode,然后查内容查属性。

3️⃣软硬链接

本质区别:有没有独立的inode

🍙软链接

软链接有独立的inode,软链接是一个独立的文件

应用:相当于windows下的快捷方式

特性:可以理解成为:软链接的文件内容,是指向的文件对应的路径!

ln -s 文件 软链接文件名

🌰建立一个软链接

🌰 软链接如同Windows下的快捷方式

🍙硬链接

硬链接没有独立的inode,硬链接不是一个独立的文件(有被链接文件的inode)

创建硬链接就是在指定的目录下,建立了 文件名 和 指定inode的映射关系。

ln 文件 硬链接文件名

🌰建立一个硬链接

硬链接没有独立的inode!也就是说硬链接不是一个独立的文件!

🌰硬链接数(引用计数)

硬链接后inode与文件名映射关系增加1组,所以为2,从这里可以看出一个思想:

当我们删除一个文件的时候,并不是把这个文件inode删除,而是将这个文件的inode引用计数--。当引用计数为0的时候,这个文件,才正在删除!!(RAII思想)

🌰默认创建文件引用计数是1,创建目录引用计数是2

inode与文件名对应一组映射关系。

但目录为什么是2呢?

因为目录里面还有隐藏文件.文件,也就是说inode对应2个文件名(自己目录名,自己目录内部的文件名),所以引用计数为2。

4️⃣动态库和静态库

🍙静态库

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

🍥生成静态库

打包.o文件:ar -rc xxx.a xxx.o xxx.o
解析 ar是gnu归档工具 ar——archieve  r——replace c ——create ,把.o文件打包到.a(静态库)

🌰将myprint.o、mymath.o打包到libtest.a

myprint.h代码:

#pragma once#include<stdio.h>
#include<time.h>extern void Print(const char* str);

myprint.c代码:

#include"myprint.h"void Print(const char* str)
{printf("%s[%d]\n",str,(int)time(NULL));
}

mymath.h代码:
 

#pragma once#include<stdio.h>extern int addToTarget(int form,int to);

mymath.c代码:

#include"mymath.h"int addToTarget(int form,int to)
{int sum=0;for(int i=form;i<=to;i++){sum+=i;}return sum;
}

Makefile:

libtest.a:mymath.o myprint.oar -rc libtest.a mymath.o myprint.o
mymath.o:gcc -c mymath.c -o mymath.o -std=c99
myprint.o:gcc -c myprint.c -o myprint.o -std=c99.PHONY:clean
clean:rm -rf *.o *.a 
静态库生成图

🍥使用静态库

gcc main.c -I 指定头文件搜索路径 -L 指定库文件搜索路径 -l使用哪个库

🌰使用上面生成的libtest.a静态库

修改Makefile文件,将头文件放到include目录中,静态库放到lib目录中。

libtest.a:mymath.o myprint.oar -rc libtest.a mymath.o myprint.o
mymath.o:gcc -c mymath.c -o mymath.o -std=c99
myprint.o:gcc -c myprint.c -o myprint.o -std=c99.PHONY:output
output:mkdir -p libmkdir -p includecp -rf *.h includecp -rf *.a lib.PHONY:clean
clean:rm -rf *.o *.a lib include

使用静态库生成可执行文件:

🍙动态库

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

🍥生成动态库

生成动态库的必须加 -fPIC 生成二进制文件

-shared告诉gcc生成动态库

gcc -fPIC -c xxxx.c -o xxxx.o //生成动态库必须加-fPIC
gcc -shared xxxx.o -o libxxxx.so  //-shared告诉gcc生成动态库

🌰生成libtest.so动态库

编写Makefile文件:

libtest.so:mymath_d.o myprint_d.ogcc -shared mymath_d.o myprint_d.o -o libtest.so
mymath_d.o:mymath.cgcc -fPIC -c mymath.c -o mymath_d.o -std=c99
myprint_d.o:myprint.cgcc -fPIC -c myprint.c -o myprint_d.o -std=c99.PHONY:output
output:mkdir -p libmkdir -p includecp -rf *.h includecp -rf *.so lib.PHONY:clean
clean:rm -rf *.o  *.so lib include
生成动态库

🍥使用动态库

动态库的使用和静态库是一样的。

gcc main.c -I 指定头文件搜索路径 -L 指定库文件搜索路径 -l使用哪个库

🌰main.c使用动态库libtest.so

查看程序链接的库(动态库):ldd

ldd 可执行程序    //查看程序链接的库

🍙同时存在使用静态库还是动态库?

问题:假设现在既有静态库又有动态库,那么程序默认链接的是哪种库?

修改Makefile文件:

.PHONY:all
all:libtest.so libtest.alibtest.so:mymath_d.o myprint_d.ogcc -shared mymath_d.o myprint_d.o -o libtest.so
mymath_d.o:mymath.cgcc -fPIC -c mymath.c -o mymath_d.o -std=c99
myprint_d.o:myprint.cgcc -fPIC -c myprint.c -o myprint_d.o -std=c99libtest.a:mymath.o myprint.oar -rc libtest.a mymath.o myprint.o
mymath.o:gcc -c mymath.c -o mymath.o -std=c99
myprint.o:gcc -c myprint.c -o myprint.o -std=c99.PHONY:clean
clean:rm -rf *.o *.a *.so 

现象:

验证发现同时存在静态库和动态库默认使用的是动态库

那么如何在这种情况使用静态库呢?  -static  指定静态链接

-static的意义:摒弃默认优先使用动态库的原则,而是直接使用静态库。

使用ldd查看链接的动态库,报错显示:不是动态可执行文件,也就是说使用的是静态库!!

🍙特点总结

🍥静态库特点

                优点:

                ①静态库被打包到应用程序中加载速度快
                ②发布程序无需提供静态库,移植方便

                缺点:

                ①相同的库文件数据可能在内存中被加载多份,消耗系统资源,浪费内存
                ②库文件更新需要重新编译项目文件,生成新的可执行程序,浪费时间

🍥动态库特点

                优点:

                ①可实现不同进程间的资源共享
                ②动态库升级简单,只需要替换库文件,无需重新编译应用程序
                ③可以控制何时加载动态库,不调用库函数动态库不会被加载                                 

                缺点:

                ①加载速度比静态库慢
                ②发布程序需要提供依赖的动态库


        文末结语,开篇解释缓冲区以及意义,并验证了用户级缓冲区的刷新策略,接下来谈文件系统,首先介绍磁盘的存储结构(包括物理结构和抽象结构),介绍inode和文件名之间的关系,软硬链接的使用,最后讲解动静态库,详细说明如何制作并使用动静态库,并探究了动静态库同时存在时默认使用动态库,以及想使用静态库的解决方案,最终总结动静态的特点。本篇旨在分享记录知识,如有需要,希望能有所帮助!!感谢观看!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MCU的类型和应用领域简介

MCU&#xff08;Microcontroller Unit&#xff09;根据存储器类型可分为无片内ROM型和带片内ROM型。无片内ROM型的芯片需要外接EPROM才能应用&#xff0c;而带片内ROM型则有不同的子类型&#xff0c;如片内EPROM型、MASK片内掩模ROM型和片内Flash型。 MCU还可以按照用途分为通…

Nodejs实现读写文件和文件流

在Nodejs中&#xff0c;文件操作是非常常见的任务之一。它允许我们读取和写入文件&#xff0c;以及处理大型文件而不会消耗太多内存。本篇博文将会首先介绍一下文件和文件流的区别&#xff0c;然后全面介绍如何在Nodejs中实现文件操作和读写&#xff0c;包括使用文件系统模块&a…

vxworks文件系统分析

参考https://www.freebuf.com/articles/endpoint/335030.html 测试固件 https://service.tp-link.com.cn/detail_download_7989.html 固件提取 binwalk解压固件&#xff0c;在第一部分即为要分析的二进制文件&#xff0c;可以拖进ida分析 设置为arm小端字节序&#xff0c;点…

IL汇编语言读取控制台输入和转换为整数

新建一个testcvt.il&#xff1b; .assembly extern mscorlib {}.assembly Test{.ver 1:0:1:0}.module test.exe.method static void main() cil managed{.maxstack 1.entrypointldstr "\n请输入一个数字:"call void [mscorlib]System.Console::Write(string)call st…

目标检测中的IOU

IOU 什么是IOU?IOU应用场景写代码调试什么是IOU? 简单来说IOU就是用来度量目标检测中预测框与真实框的重叠程度。在图像分类中,有一个明确的指标准确率来衡量模型分类模型的好坏。其公式为: 这个公式显然不适合在在目标检测中使用。我们知道目标检测中都是用一个矩形框住…

npm更新和管理已发布的包

目录 1、更改包的可见性 1.1 将公共包设为私有 ​编辑 使用网站 使用命令行 1.2 将私有包公开 使用网站 使用命令行 2、将协作者添加到用户帐户拥有的私有包 2.1 授予对Web上私有用户包的访问权限 2.2 从命令行界面授予私有包访问权限 2.3 授予对私有组织包的访问权限…

Python导出SqlServerl数据字典为excel

sql代码 SELECTtableName D.name ,tableIntroduce isnull(F.value, ),sort A.colorder,fieldName A.name,catogary B.name,bytes A.Length,lengths COLUMNPROPERTY(A.id, A.name, PRECISION),scales isnull(COLUMNPROPERTY(A.id, A.name, Scale), 0),isOrNotNull Cas…

Linux新手小程序——进度条

前言 目录 前言 需要先了解 1.\r和\n 2.缓冲区 一.理解字符的含义&#xff1a; 学习c语言时&#xff0c;我们可以粗略把字符分为可显字符和控制字符. 在按回车换到下一行开始的操作时&#xff0c;实际上是进行了两个操作&#xff1a;1.让光标跳到下一行&#xff08;只…

【css问题】flex布局中,子标签宽度超出父标签宽度,导致布局出现问题

场景&#xff1a;文章标题过长时&#xff0c;只显示一行&#xff0c;且多余的部分用省略号显示。 最终效果图&#xff1a; 实现时&#xff0c;flex布局&#xff0c;出现问题&#xff1a; 发现text-overflow: ellipsis不生效&#xff0c;省略符根本没有出现。 而且因为设置了 …

【IMX6ULL驱动开发学习】21.Linux驱动之PWM子系统(以SG90舵机为例)

1.设备树部分 首先在 imx6ull.dtsi 文件中已经帮我们定义好了一些pwm的设备树节点&#xff0c;这里以pwm2为例 pwm2: pwm02084000 {compatible "fsl,imx6ul-pwm", "fsl,imx27-pwm";reg <0x02084000 0x4000>;interrupts <GIC_SPI 84 IRQ_TYP…

【总结】p49常见问题和快捷键汇总

p49常见问题和快捷键汇总 基础概念常用快捷键汇总编辑器快捷键&#xff08;不包括视口操作&#xff09;蓝图快捷键 中英文命名注意事项帧和秒的概念带星号的文件的意思编译的作用实例和原素材情景关联返回的快捷键 虚幻引擎闪退问题 基础概念 常用快捷键汇总 编辑器快捷键&am…

中国政府版 Windows 10 开发完成,即将大规模推广

早在今年 3 月 20 日&#xff0c;就有媒体曝光中国政府专用 Windows 10 已经完成第一版。而就在今天微软在上海举办的发布会中&#xff0c;微软再次透露了中国政府版 Windows 10 的最新情况——已经开始试点测试。这就意味着政府版 Windows 10 或很快大规模推广。 据了解&#…

【设计模式】工厂模式

什么是工厂模式&#xff1f; Java的工厂模式是一种创建型设计模式&#xff0c;它提供了一种创建对象的最佳方式。在工厂模式中&#xff0c;我们在创建对象时不会对客户端暴露创建逻辑&#xff0c;而是通过使用一个共同的接口来指向新创建的对象。这种类型的设计模式属于创建型…

【C#学习笔记】引用类型(1)

文章目录 引用类型class匿名类 记录引用相等和值相等record声明 接口delegate 委托合并委托/多路广播委托 引用类型 引用类型的变量存储对其数据&#xff08;对象&#xff09;的引用&#xff0c;而值类型的变量直接包含其数据。 对于引用类型&#xff0c;两种变量可引用同一对…

10.物联网操作系统之低功耗管理

一。低功耗管理概念及其应用 1.STM32低功耗设计详解 STM32的电源管理系统主要分为&#xff1a; 备份域 调压器供电电路 ADC电源电路 2.低功耗模式 1.运行模式 2.睡眠模式 3.停机模式 4.待机模式 &#xff08;1&#xff09;睡眠模式 在睡眠模式中&#xff0c;仅关闭了内核时钟&…

数据结构——二叉树

本章代码仓库&#xff1a;堆、二叉树链式结构 文章目录 &#x1f36d;1. 树&#x1f9c1;1.1 树的概念&#x1f9c1;1.2 树的结构 &#x1f36c;2. 二叉树&#x1f36b;2.1 二叉树的概念&#x1f36b;2.2 特殊的二叉树&#x1f36b;2.3 二叉树的性质&#x1f36b;2.4 二叉树的存…

Julia 日期和时间

Julia 通过 Dates 模块提供了以下三个函数来处理日期和时间&#xff1a; Date&#xff1a;表示日期&#xff0c;精确到日&#xff0c;只显示日期。DateTime&#xff1a;表示日期和时间&#xff0c;精确到毫秒。DateTime&#xff1a;表示日时间&#xff0c;精确到纳秒&#xff…

【数据库】将excel数据导入mysql数据库

环境&#xff1a;Windows10 mysql8以上 将你要导入的excel表另存为txt格式 打开txt格式文件&#xff0c;删除表头行并另存为并更改编码方式&#xff08;由于与数据库的编码不同&#xff0c;会导致导入报错&#xff09; 通过命令行登录数据库 winr cmd进入 进入装mysql的目录位…

基于BIM+AI的建筑能源优化模型【神经网络】

推荐&#xff1a;用 NSDT设计器 快速搭建可编程3D场景。 AEC&#xff08;建筑、工程、施工&#xff09;行业的BIM 技术&#xff0c;允许在实际施工开始之前虚拟地建造建筑物&#xff1b; 这带来了许多有形和无形的好处&#xff1a;减少成本超支、更有效的协调、增强决策权等等。…

Windows批处理基础

一、【echo】显示文本内容 echo | Microsoft Learnhttps://learn.microsoft.com/zh-cn/windows-server/administration/windows-commands/echo 显示消息或者打开或关闭命令回显功能。 如果不结合任何参数使用&#xff0c;echo 会显示当前回显设置。 1.1、echo显示文本常用命…