Linux知识点 -- 基础IO(三)

Linux知识点 – 基础IO(三)


一、理解文件系统

1.磁盘文件

磁盘是永久性存储介质,如:SSD,U盘,光盘,磁带等;磁盘是外设,是我们计算机中唯一的机械设备,因此读取速度很慢;

  • 磁盘物理结构:
    在这里插入图片描述
    磁盘中有盘片、磁头、伺服系统、音圈马达等;
    磁盘面上会存储数据,由于计算机只认识二进制,因此用磁极来表示0和1,向磁盘写入,本质就是改变磁盘上的正负极;

  • 磁盘存储结构:
    在这里插入图片描述
    在这里插入图片描述
    磁盘中的每一个盘面都分为多个不同的磁道,每个磁道又分为不同的扇区,磁盘的最小存储单元是一个扇区大小是512byte

  • 如何将数据写入指定的扇区?
    这是磁盘的CHS寻址:
    (1)在哪一个面上;
    (2)在哪一个磁道上;
    (3)在哪一个扇区上;

  • 磁盘的抽象结构:
    我们将磁盘的磁道展开成为线性结构:
    在这里插入图片描述
    这样来看磁盘的结构就像是一个数组,访问一个扇区,只需要知道这个扇区的数组下标就好;
    我们平常所说的磁盘分区,就是将磁盘分为几个不同的数组:
    在这里插入图片描述
    将数据存储到该磁盘就变成了将数据存储到该数组;
    找到磁盘特定扇区的位置就变成了找到数组特定的位置;
    对磁盘的管理就变成了对数组的管理;

2.文件系统的存储结构

其中一个磁盘分区展开后的结构如下:
在这里插入图片描述
其中Blokck group就是用来存储文件的;
Linux在存储文件的时候,将内容和属性分开存储;
虽然磁盘的基本单位是扇区(512字节),但是操作系统(文件系统)和磁盘进行IO的基本单位是4KB(block的大小),因此,磁盘又被称为块设备;
这样设计的原因是:

  • IO基本单位设计的太小的话,会导致效率变低;
  • 如果OS使用和磁盘一样的基本单位,如果磁盘的基本单位更改了,那么操作系统也需要更改,所以需要对硬件和软件进行解耦;

在Blokck group中,有如下几个分区:

  • Super Block:存储整个分区的文件系统的属性信息;并不是每个快组都有SB模块,而是分发在分区中某几个快组中,为的是进行备份,防止丢失;
  • Group Descriptor Table(GDT)块组描述符,描述各个block的信息,如大小,使用情况,有多少inode等;
  • Block Bitmap:块组位图,其中的比特位和特定的block是一一对应的,如果该位为1,就表示该block已被占用,否则表示可用;
  • Inode Bitmap:inode位图,其中的比特位和特定的inode是一一对应的,如果该位为1,就表示该inode已被占用,否则表示可用;
  • Inode Table:inode是一个大小为128字节的空间,保存的是对应文件的属性,是该块组内,所有文件的inode空间的集合;需要标识唯一性,每一个inode块,都需要有一个inode编号,一般而言一个文件一个inode,一个inode编号;
  • Data blocks:多个4KB(扇区 * 8)大小的集合,保存的都是特定文件的内容;

格式化:将块组分割成上面的内容,并且写入相关的管理数据,每一个块组都如此操作,整个分区就被写入了文件系统信息;

一个文件可能对应多个block,找到文件,只需找到对应的inode编号,就能找到该文件的inode属性集合,文件内容所占的块组编号也在inode信息中的blocks数组中;
在这里插入图片描述
如果文件特别大,一个块组中放不下,需要存放到其他块组中,那么,inode中的blocks数组前m个block存放的是这个文件的数据,数组后面的block存放的是剩下数据存放的block块号,相当于一个间接寻址

3.inode与文件名的关系

  • Linux系统寻找文件的过程:
    由文件inode编号 -> 找到特定的bg块组 -> 对应的inode -> 属性 -> 内容;

那我们是如何得到文件的inode编号的?依托于目录结构;
Linux中,文件属性里面,没有文件名这样的说法;

  • (1)一个目录下,可以保存很多文件,但是这些文件没有重复的文件名;
  • (2)目录也是文件,有自己的inode,有自己的data block;

在Linux系统中存储文件,用户根据文件名创建和区分文件,但是写入系统时,系统只会为文件分配唯一的inode编号,然后建立文件名和inode编号的映射关系表,是一个KV结构,用户提供文件名,OS提供inode编号,所以用户能够通过文件名搜索到文件;

目录的权限:

  • 在目录中创建文件必须有写权限,是因为创建文件必须向目录写入该文件的文件名和inode的映射关系;
  • 显示文件名和属性必须有目录的读权限,因为要读取到文件的inode,才能读取属性

一个块组中,inode和data blocks的数量都是一定的,存在inode还有,但是block没了;或者inode没了,但是block还有的情况;

二、软硬链接

1、软链接

  • 创建软链接:
    在这里插入图片描述
    ln:创建链接;
    -s:软链接;

    ls -i指令能够看出文件的inode:
    在这里插入图片描述
    可以看到,软链接是有独立的inode的,是一个独立的文件;

  • 软链接的作用:
    在这里插入图片描述
    在bin/exe目录下的可执行程序test,在现在的目录下建立软链接:
    在这里插入图片描述
    直接运行软链接:
    在这里插入图片描述
    可以看出运行成功;
    软链接的文件内容,是指向对应文件的路径;可以理解为win下的快捷方式;

2.硬链接

  • 创建硬链接:
    在这里插入图片描述
    在这里插入图片描述
    可以看出,硬链接文件没有自己独立的inode,这也是软硬链接的本质区别;

  • 硬链接的作用:
    在这里插入图片描述
    从上图可以看出,硬链接和原文件属性中的这个数字都为2,这个属性是硬链接数
    硬链接就相当于给文件起别名,建立了文件名和指定inode的关系;
    当我们删除硬链接指向的文件时,硬链接inode还存在,属性中的硬链接数从2变成了1;
    在这里插入图片描述

硬链接没有独立的inode,不是一个独立的文件,创建硬链接,不是真正的创建新文件,就是在指定目录下,建立了文件名和指定inode的映射关系;
硬链接数就相当于一个引用计数,每创建一个硬链接时,引用计数就加一;当我们删除文件时,并不是把这个文件inode删除了,而是将这个文件的inode引用计数减一,当引用计数为0的时候,才真正删除;

  • 硬链接的用途:
    在这里插入图片描述
    新建一个普通文件,硬链接数是1;
    新建一个目录,硬链接数是2;

    在这里插入图片描述
    这是因为目录内部的 . 文件也影射了该目录的inode,两个硬链接,一个是自己的目录名链接inode,另一个是目录内部的 . 文件链接inode;
    在这里插入图片描述
    在test目录下再创建一个目录,可以发现test的硬链接数变为了3,这是因为ss目录中的 … 文件映射上级路径test的inode;

三、动静态库

1.库

  • 库中没有main函数;
  • 如果我只把.o和.h文件给别人,是可以使用的;
  • 静态库后缀为:.a;
  • 动态库后缀为:.so;

2.生成静态库

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
生成的.o文件给别人是直接可以使用的,但是很麻烦;
在这里插入图片描述
在这里插入图片描述
静态库的生成过程就是把.o文件打包的过程;
在这里插入图片描述

  • ar:归档文件;

  • -r:替换;

  • -c:创建;

  • libhello.a:静态库文件,必须以lib开头,.a结尾;

  • 使用makefile实现自动打包:
    在这里插入图片描述

  • 库的发布:
    库的发布文件夹里需要有两个子文件夹:
    -inlcude:保存库的独有头文件;
    -lib:保存对应的库文件;

    在makefile中完成自动化创建:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

3.静态库的使用

在这里插入图片描述

  • (1)拷贝库文件到系统目录下:
    gcc头文件的默认搜索路径是:/usr/include
    gcc头库件的默认搜索路径是:/lib64 or /usr/lib64

    在这里插入图片描述
    这时main函数中不会报错,但是编译时会报错,因为这是我们自己提供的第三方库,必须要告知C语言我们需要连接哪个库;
    在这里插入图片描述
    -l库名:指定链接库(没有空格),真正的库名是去掉前缀lib和后缀的
    运行结果:
    在这里插入图片描述
    但是这种方法会污染官方库,不建议使用;

  • (2)让GCC在指定目录下搜索头文件和库:
    在这里插入图片描述
    -I 目录:在指令目录下搜索头文件;
    -L 目录:在指定目录下搜索库文件;
    由于该目录下可能有多个库文件,因此需要指定库文件;

    在这里插入图片描述
    在这里插入图片描述

4.生成动态库

在这里插入图片描述
在这里插入图片描述
-fPIC:生成一个与位置无关的目标二进制文件;
在这里插入图片描述
-shared:制作动态库,而不是可执行程序;

  • 用makefile实现:
    在这里插入图片描述
    动静态库一起生成,并发布output文件夹;
    在这里插入图片描述
    在这里插入图片描述
    打包库:
    在这里插入图片描述

5.使用动态库

在这里插入图片描述
从上面看出,直接使用gcc指定头文件和库文件的方法来加载动态库,能够编译过,但是无法运行程序,使用ldd命令查看动态链接时,发现libhello.so动态库链接找不到
ldd 可执行程序:查看该程序的动态链接;
我们发现gcc是默认动态链接的,但是没有链接上;
前面静态库是因为只有静态库,gcc只能静态链接:
在这里插入图片描述
使用静态库时就没有链接libhello.so;
-static:摒弃默认优先使用动态库的原则,直接使用静态库的方案;
在这里插入图片描述
在上面我们已经制定了动态库的路径,动态库还是无法链接,这是因为我们是给gcc指定的链接,这和动态库的加载过程有关;

  • 动态库的加载过程:
    动态库是一个独立的库文件,动态库和可执行程序,是可以分配加载的;
    静态库的加载是直接将库代码加载到了内存里面,直接进入进程的代码区;
    动态库是可以分批加载的,在将可执行程序加载到内存后,可执行程序中是有对应的库链接信息的;
    在编译链接时,需要加载库时,就可以加载动态库了,是分开进行的,这时再将动态库代码加载到内存中,在页表建立库代码与共享区的联系;
    在代码区函数跳转访问库函数的时候,直接跳转到共享区,根据页表找到内存中的库代码去执行;

    在这里插入图片描述

  • 方法一:添加环境变量
    我们上面指定动态库路径是给gcc指定的,动态库是运行时加载的,这时就与gcc没有关系了,需要给系统说;
    在这里插入图片描述
    $LD_LIBRARY_PATH是系统环境变量,加载库的路径;
    库的绝对路径:
    在这里插入图片描述
    导入环境变量:
    在这里插入图片描述
    运行可执行程序:
    在这里插入图片描述
    这种方法的缺点是:退出登陆后,环境变量会丢失,因为这是内存级的环境变量,只能做一个临时方案;

  • 方法二:修改配置文件
    在这里插入图片描述
    这个路径中包含自定义搜索库路径的永久解决方案;
    在这里插入图片描述
    直接创建文件,然后将目录放进该文件中;
    在这里插入图片描述
    在这里插入图片描述
    更新系统权限:
    在这里插入图片描述
    运行:
    在这里插入图片描述
    在这里插入图片描述

  • 方法三:在系统目录下建立软链接
    在这里插入图片描述
    运行:
    在这里插入图片描述

6.为什么要有库

  • 站在使用者的角度:
    库的存在,可以大大减少我们的开发周期,提高软件本身的质量;
  • 站在开发库的角度:
    简单,且能够保证代码安全;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值