当前位置: 首页 > news >正文

文件系统与动静态库的基本了解

目录

  • 文件系统与动静态库的基本了解
    • 文件系统
      • 了解Access Modify Change
      • inode
      • 硬链接
      • 软链接
    • 静态库与动态库
      • 概念
      • 静态库的制作
      • 使用静态库
      • 动态库的制作
      • 使用动态库
      • 总结如何制作

文件系统与动静态库的基本了解

文件系统

了解Access Modify Change

当文件没有被打开时,他们存放在哪里呢?是磁盘上面,我们可以通过命令行上面输入ls -l(读取存储在磁盘上的文件信息,然后显示出来) 或者 stat filename来查看文件信息,ls命令已经很熟悉了,我们这里来看看stat命令
这里我们来着重了解一下这三个时间:

  • Access:最近一次访问时间
  • Modify:最近一次修改时间–>指文件内容
  • Change:最后一修改时间–>指文件属性

我们经常使用的Makefile和make,我们知道当我们不做修改时,如果已经make过一次之后,再次make就会报错说文件已经存在(虚拟依赖除外),那么操作系统到底为什么能够知道文件已经编译过不需要在编译了呢?原因就在于Modify也就是修改时间,如果一个文件刚刚编译形成了一个可执行程序,那么形成的可执行程序它的修改时间一定比文件的修改时间要晚,这样Makefile就可以根据两个文件的最近一次的修改时间来判断是否需要继续编译,以下是例子:

  • 要注意虽然说Access是最近一次的访问时间,可是linux内核版本在2.6左右往上,这个访问时间都不会被立即刷新,要有一定的时间间隔,OS才会自动进行更新时间,主要是因为访问这一操作比较频繁,如果频繁的刷新会让系统变卡
  • 当我们修改文件内容的是时候,大概率是会修改文件的属性的,比如:可能会更改文件的大小(文件大小也是属性)

inode

Linux上:文件名在系统层面没有意义,文件名是给我们用户用的,Linux中真正标识一个文件,是通过文件的inode编号来标识的,当我们的文件没有被加载到内存中的时候,它们就存储在磁盘上面,磁盘中最小的存储单元是扇区(1扇区=512Bytes),文件系统的最小存储单元是block(1Block=4kb=8扇区)


我们都知道磁盘上面有很多的扇形分区,如果我们把扇形的分区抽象成长方形来看待我们就会得到这样一个图:

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

  • Block Group:ext2文件系统会根据分区的大小划分数个Block Group都有这相同的结构组成

  • 超级块(Super Block):存放文件系统本身的结构信息。记录信息主要有:block和inode的总量,未使用的block和inode的数量,一个Block和一个inode的大小,最近一次的挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Supper Block的信息被破坏就相当于整个文件系统结构就被破坏了

  • GDT(Group Descriptor Table),组描述符表。由很多组描述符组成,整个分区分成多少个组就对应有多少个组描述符。每个组描述符(Group Descriptor)存储一个组的描述信息,例如在这个组中从哪里开始是inode表,从哪里开始是数据块,空闲的inode和数据块还有多少个等等。

  • 块位图(Block Bitmap):这里面记录着Data Block中哪个数据块被占用,哪个数据块没被占用

  • inode位图(inode Bitmap):每个bit表示一个inode空间是否空闲可用

  • inode节点表(inode Table):存放文件属性如文件大小,所有者,最近修改时间等等

  • 数据区(Data blocks):存放文件内容


将属性和文件数据分开存放实际上应该如何实现呢?

我们以touch一个文件为例来看:
创建文件主要有以下四个操作:

  1. 存储属性

    内核先找到空闲的inode节点(这里是1049849),内核把文件信息记录到其中

  2. 存储数据

    该文件需要三个磁盘块,内核找到了三个空闲块400,600,800.将内核缓冲区的第一块数据复制到400接着是600依次类推

  3. 记录分配情况

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

  4. 添加文件名到目录

    新的文件名file.txt。Linux如何在当前文件目录中记录这个文件内核将入口(149849,file.txt)添加到目录文件,文件名和inode之间的对应关系将文件名和文件内容及其属性连接起来


几个相关问题:(仅是我的理解)

目录的本质是什么呢?

  • 本质可以理解为存放了文件名和对应的inode的链接关系的文件,可以通过文件名去找到对应的inode,从而可以通过inode table来查看文件的属性或者内容数据

删除的本质是什么呢?

  • 删除的本质其实就是把inode bitmap中的对应位置改为未被占用即可,这也是有时候误删之后可以恢复的原理,当如果误删掉一个文件之后如果自己不会恢复就尽量保持原样,不要再进行多余的操作,去找专业的人去解决,因为保持刚删除后的样子能最大程度保证删除之后的数据块没有被覆盖,这样恢复的可能会更大(也就是把inode和数据块之间重新建立链接)

硬链接

首先怎么使用硬链接,在shell中的做法是:ln 被链接的文件路径及文件名 文件名 我们看到,真正找到磁盘上文件的并不是文件名,而是inode。 其实在Linux中可以让多个文件名对应于同一个inode,硬链接本质就不是一个独立的文件,而是一个文件名和inode编号的映射关系,因为它没有自己的inode

  • file1.txt和hard.txt的链接状态完全相同,它们被称为指向文件的硬连接。内核记录了这个连接数inode是1053256硬连接数是2
  • 我们在删除文件时干了两件事:
    1. 在目录中将对应的记录删除
    2. 将硬连接数-1,如果为0,则将对应的磁盘释放
  • 目录文件在创建时就有两个硬连接

软链接

用法与硬连接相同只是多了个-s:ln -s 要链接文件的路径以及文件名 文件名

  • 软链接形成的是一个新的文件,因为它具有自己的inode属性,也有自己的数据块(保存的是指向文件的所在路径和文件名)
  • 如果被链接的文件被删除,那么链接文件也会失效

静态库与动态库

概念

在Linux中如果是动态库,库文件是以.so为后缀的;静态库是以.a为后缀的;在windows中动态库.dll,静态库.lib

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库
  • 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
  • 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
  • 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间
  • ldd filename:显示可执行程序依赖的库,这里就是libc.so.6库名字就是c库
  • 库文件的命名:libXXXX.so or libXXXX.a-…
  • 动静态库的名字是去掉lib前缀和.so-或者.a-后缀剩下的部分
  • 一般云服务器可能没有内置语言的静态库,而只有动态库可以自己添加一下sudo yum install glibc -static


同样file命令也可以查看可执行程序是什么链接,这里就是动态链接,使用的是共享库


静态库的制作

首先我们我们先了解一下原理,我们都知道一个文件想要到可执行,需要以下几个步骤:预处理,编译,汇编,链接。其中汇编之后会形成一个.o下标的二进制文件,并不可以被直接执行,叫可重定向目标文件(-c 是开始进行程序的编译,完成汇编工作就停下),这个.o文件就是制作动静态库所需的文件,因为其本身已经具有可执行的属性了,只是没有被链接,动静态库其实也就是打包这些.o文件并且附代上.h的头文件,了解到这里我们开始进行一个简单的静态库的制作

  • 制作静态库我们可以使用ar -rc打包静态库,ar是gnu归档工具,rc表示replace and create

  • 查看已经制作完成的静态库:ar -tv查看打包内容

    t:列出静态库中的文件
    v:verbose 详细信息

举例:

  1. 首先我们先创建四个文件,文件内容如下:

    //add.h,add.c,sub.h,sub.c
    //sub.h
    #include<stdio.h>
    extern int sub(int x,int y);
    //sub.c
    #include"sub.h"
    int sub(int x,int y)
    {return x-y;
    }
    //add.h
    #include<stdio.h>
    extern int add(int x, int y);
    //add.c
    #include "add.h"
    int add(int x,int y)
    {return x + y;
    }
    
  2. 创建出Makefile文件

    • 我们之前写的那些代码也都用了库(如c库),为什么没有指名这些选项呢?—>之前的库,在系统的默认路径下:/lib64/usr/lib, /usr/include等等
    • 所以如果我们不想带这些选项,我们可以直接把对应的库和头文件拷贝到默认路径下首先是可行的,但是非常不推荐这样做,这会污染库,有时如果库的一些文件与拷贝文件重名还会覆盖掉原先的库
    • 一般软件安装的过程其实也就是上面的过程

这样就把静态库制作完成并打包了

使用静态库

我们制作好了静态库应该如何使用呢?其实也就是链接的过程,我们需要先写一段简单的代码:

//因为头文件不在同一目录下,所以需要指定一下路径
#include "./libs/add.h"
#include "./libs/sub.h"
int main()
{int x=20;int y=10;printf("add = %d\n",add(x,y));printf("sub = %d\n",sub(x,y));return 0;
}

在这里插入图片描述
这样就可以去执行了,因为静态链接的特性,编译的时候会把静态库代码拷贝进我们所写的测试代码中去,所以只要指定好路径,编译形成可执行文件之后就可以直接运行了

动态库的制作

动态库的制作原理和静态库基本一致,总的来说就是打包.o文件具体我们来看操作,还是上面的例子:

  1. 创建四个文件并写上相应的内容

    //sub.h sub.c add.h add.c
    
  2. 创建出Makefile文件

    • gcc -fPIC -c $<产生.o目标文件,程序内部的地址解决方案是:与位位置无关,库文件可以在内存的任何位置加载,而且不影响和其他程序的关联性(-fPIC的作用)
    • -shared就是形成一个动态链接的共享库

之后直接make,make libd即可形成动态库

使用动态库

在使用之前我们得先认识到一个东西:文件编译形成可执行文件的是编译器,而形成的可执行文件要运行,需要的是加载器,两者不是同一个东西

使用动态库同样需要写一个简单的代码

#include "./libd/add.h"
#include "./libd/sub.h"
int main()
{int x=20;int y=10;printf("add = %d\n",add(x,y));printf("sub = %d\n",sub(x,y));return 0;
}

然后开始写Makefile,内容与静态库的使用基本一致
静态库这样就直接可以运行了,但是动态库不行,这只是代表了编译能通过,但是运行时会报错
这种情况的解决方法有很多种但是这里推荐一种使用LD_LIBRARY_PATH具体用法如下:

  • export LD_LIBRARY_PATH = 库所在的绝对路径
  • 为什么这里不需要指定库名(这里是dynamic)呢?从ldd可以看出可执行文件已经知道所链接的库名了,只是没有路径找不到
  • 这种方法需要每一次打开端口的时候都设置一次,export只适用于当前登录,退出之后所做的修改就清除了

还有其他的方法就是:

  1. 拷贝.so文件到系统共享库路径下,一般指/usr/lib不过不推荐
  2. ldconfig 配置/etc/ld.so.conf.d/,ldconfig更新

总结如何制作

  1. 所有的源代码,都需要先被编译成为.o(可重定向目标文件)
  2. 制作动静态库的本质就是将所有的.o打包(使用ar或者gcc来进行打包)
  3. 交付头文件 + -.a 或者 -.so 文件

gcc和g++优先链接动态

相关文章:

文件系统与动静态库的基本了解

目录文件系统与动静态库的基本了解文件系统了解Access Modify Changeinode硬链接软链接静态库与动态库概念静态库的制作使用静态库动态库的制作使用动态库总结如何制作文件系统与动静态库的基本了解 文件系统 了解Access Modify Change 当文件没有被打开时&#xff0c;他们存…...

netty——IO、NIO、AIO进化之路

IO、NIO、AIO进化之路BIO——同步阻塞IO伪异步阻塞IONIO——同步非阻塞IOAIO——异步IO总结本文会说明各种IO的特点、分别解决了什么样的问题做一个分析阐述&#xff0c;并结合Java代码例子来辅助理解&#xff0c;像这些的历史演进和详细的底层原理网上很多&#xff0c;所以我们…...

AI稳定生成图工业链路打造

前沿这篇文章会以比较轻松的方式&#xff0c;跟大家交流下如何控制文本生成图片的质量。要知道如何控制文本生成质量&#xff0c;那么我们首先需要知道我们有哪些可以控制的参数和模块。要知道我们有哪些控制的参数和模块&#xff0c;我们就得知道我们文本生成图片的这架机器或…...

20230220华南金牌主板u盘启动

20230220华南金牌主板u盘启动 2023/2/20 10:29 百度搜索&#xff1a;华南金牌主板u盘启动 https://www.zhihu.com/question/498121895?utm_id0 华南金牌主板b85u盘启动怎么设置? 华南金牌主板b85u盘启动怎么设置 海的那边 上小学后才发现还是幼儿园好混…… 华南一般是F7和F1…...

测试团队都在用哪些不错的测试用例管理平台?盘点6大主流测试管理系统

测试团队使用的主流测试用例管理平台&#xff1a;1.PingCode &#xff1b;2.TestRail&#xff1b;3.Testlink&#xff1b;4.ZephyrJira&#xff1b;5.TestCenter&#xff1b;6.飞蛾。目前市面上的测试用例管理工具有很多&#xff0c;但由于针对的项目、领域、目标用户&#xff…...

linux 系统编程之线程

线程 文章目录线程1 线程概念2 NPT安装线程 man page&#xff1a;查看指定线程的 LWP 号&#xff1a;3 线程的特点4 线程共享资源5 线程非共享资源6 线程的优缺点7线程常用操作1 线程号pthread_self函数&#xff1a;pthread_equal函数:参考代码2 错误返回值分析参考代码3 线程的…...

从0开始学python -35

Python3 File(文件) 方法 open() 方法 Python open() 方法用于打开一个文件&#xff0c;并返回文件对象。 在对文件进行处理过程都需要使用到这个函数&#xff0c;如果该文件无法被打开&#xff0c;会抛出 OSError。 注意&#xff1a;使用 open() 方法一定要保证关闭文件对…...

1.14 golang中的结构体

1. 结构体 Go语言中没有“类”的概念&#xff0c;也不支持“类”的继承等面向对象的概念。Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。 1.1. 类型别名和自定义类型 1.1.1. 自定义类型 在Go语言中有一些基本的数据类型&#xff0c;如string、整…...

原创不易,坚持更难

早上CSDN发消息&#xff0c;今天是创作满三年的纪念日&#xff0c;邀请写一篇博文&#xff0c;谈谈感受 开博原因 2020年是一个特殊的年份&#xff0c;疫情刚爆发第一年&#xff0c;也是第一次居家办公&#xff0c;从过完年就一直居家办公&#xff0c;一直居家了38天。2020年…...

计算机网络 | 谈谈TCP的流量控制与拥塞控制

文章目录一、TCP的流量控制1、利用滑动窗口实现流量控制【⭐⭐⭐】2、如何破解【死锁】局面❓二、TCP的拥塞控制1、拥塞控制的一般原理① 解决网络拥塞的误区② 拥塞控制与流量控制的关系【重点理解✔】2、TCP的拥塞控制方法① 接收窗口【rwnd】与拥塞窗口【cwnd】② 慢开始和拥…...

Flask入门(7):内置装饰器(钩子函数)

目录7.内置装饰器&#xff08;钩子函数&#xff09;7.1 before_request7.2 after_request7.3 before_first_request7.4 error_handlers7.5 template_filter7.6 template_global复习装饰器基础及其应用&#xff0c;可参考文章&#xff1a;闭包和装饰器 7.内置装饰器&#xff08…...

Java8新特性

✨作者&#xff1a;猫十二懿 ❤️‍&#x1f525;账号&#xff1a;CSDN 、掘金 、个人博客 、Github &#x1f389;公众号&#xff1a;猫十二懿 写在最前面 在企业中更多的都是使用 Java8 &#xff0c;随着 Java8 的普及度越来越高&#xff0c;很多人都提到面试中关于Java 8 也…...

哈希表题目:设计哈希集合

文章目录题目标题和出处难度题目描述要求示例数据范围解法一思路和算法代码复杂度分析解法二思路和算法代码复杂度分析题目 标题和出处 标题&#xff1a;设计哈希集合 出处&#xff1a;705. 设计哈希集合 难度 3 级 题目描述 要求 不使用任何内建的哈希表库设计一个哈希…...

java static关键字 万字详解

目录 一、为什么需要static关键字&#xff1a; 二、static关键字概述 : 1.作用 : 2.使用 : 三、static修饰成员变量详解 : 1.特点 : 2.细节 : ①什么时候考虑使用static关键字? ②静态变量和非静态变量的区别&#xff1f; ③关于静态变量的初始化问题 : ④关于静态变…...

光谱实验反射、透射光谱测量

标题反射、透射光谱测量的基本原理  暗背景/基线&#xff1a;Dark………………………………………………………………0%  &#xff08;空&#xff09;白参考&#xff1a;Reference…………………………………………………………100%  样品反射/透射光谱&#xff1a;Sampl…...

【基础算法】之 冒泡排序优化

冒泡排序思想基本思想: 冒泡排序&#xff0c;类似于水中冒泡&#xff0c;较大的数沉下去&#xff0c;较小的数慢慢冒起来&#xff08;假设从小到大&#xff09;&#xff0c;即为较大的数慢慢往后排&#xff0c;较小的数慢慢往前排。直观表达&#xff0c;每一趟遍历&#xff0c;…...

Python | 线程锁 | 3分钟掌握【同步锁】(Threading.Lock)

文章目录概念无锁加锁死锁解决死锁概念 threading.Lock 同步锁&#xff0c;可以用于保证多个线程对共享数据的独占访问。 当一个线程获取了锁之后&#xff0c;其他线程在此期间将不能再次获取该锁&#xff0c;直到该线程释放锁。这样就可以保证共享数据的独占访问&#xff0c…...

Linux下安装MySQL8.0的详细步骤(解压tar.xz安装包方式安装)

Linux下安装MySQL8.0的详细步骤 第一步&#xff1a;下载安装配置 第二步&#xff1a;修改密码&#xff0c;并设置远程连接&#xff08;为了可以在别的机器下面连接该mysql&#xff09; 第三步&#xff1a;使用Navicat客户端连接 搞了一台云服务器&#xff0c;首先要干的活就是…...

leaflet 绘制多个点的envelope矩形(082)

第082个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中如何根据多边形的几个坐标点来绘制envelope矩形。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共78行)安装插件相关API参考:专栏目标示例…...

CAJ论文怎么批量免费转换成Word

大家都知道CAJ文件吗&#xff1f;这是中国学术期刊数据库中的文件&#xff0c;这种文件类型比较特殊。如果想要提取其中的内容使用&#xff0c;该如何操作呢&#xff1f;大家可以试试下面这种免费的caj转word的方法,多个文档也可以一起批量转换。准备材料&#xff1a;CAJ文档、…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...