一、理解文件系统
使用命令查看信息
1,使用ls -l查看文件属性和文件内容
2,stat+文件名查看更多信息
3,inode
Linux中的文件分为文件属性和文件内容。文件属性又称为元信息。保存在inode结构中,inode是一个文件属性的集合。一个文件名都对应着一个inode。
我们使用 ls -i,就可以查看当前目录下文件的inode编号
我们之前在讨论进程与文件的关系的时候,讨论的都是进程与被打开文件的关系。那么没有被打开的文件存放在哪里呢?
答案是存放在磁盘上!
磁盘
概念
其实在我们讨论进程与被打开文件之间的关系的时候,就有提到过一个可执行程序就是存放在磁盘上边的。并且冯诺依曼体系结构中磁盘属于外设,并且磁盘既可以当做输入设备,又可以当做输出设备。
磁盘是一种用于存储和读取数据的设备,它通常由一个或多个盘片组成,每个盘片都有一个可读写的磁性表面。数据被存储在盘片上的磁性表面上,通过读写磁头来访问。磁盘通常被用作计算机的主要存储设备,用于存储操作系统、应用程序和用户数据。
磁盘可以分为两种类型:机械硬盘和固态硬盘。机械硬盘使用旋转的盘片和移动的磁头来读写数据,而固态硬盘则使用闪存芯片来存储数据。固态硬盘通常比机械硬盘更快,更可靠,但也更昂贵。
在计算机中,磁盘通常被分为多个分区,每个分区可以被格式化为不同的文件系统。文件系统是一种用于组织和管理文件的方式,它定义了文件和目录的结构以及如何访问它们。常见的文件系统包括FAT、NTFS、EXT4等
磁盘实物图
盘片的俯视图
磁道:一圈圈的同心圆就是磁道。
扇区:每一圈磁道被分为了不同的小份,其中一小份就为扇区。
磁盘的剖面图
这个图中有六个磁头,当磁头读取数据的时候这6个磁头是一起运动的。
先确定数据是在哪个柱面上的,然后确定是在哪个磁道上的,最后确定是在哪个扇区上的。
扇区位置的确定
首先我们要明白一个事情,虽然磁片上的同心圆从里到外半径不同,但是他们存放数据的大小是一样的,就比如最里边的那个圆的半径虽然很小但是它跟最外边的圆上存放数据的大小是一样的
页帧
我们就可以通过LBA地址来确定每个扇面的位置。
我们给每个扇区分的大小为512byte,当我们读取或访问数据的时候是以页帧的大小来访问的。虽然每个扇区有512字节的大小,但是还是太小了。页帧的大小根据文件系统不同而不同,一般页帧的大小为4KB。
磁盘的分组管理
一个磁盘太大了,因此采用的是分而治之的方式来进行分组管理的。假如有一块500G的磁盘,我们会把它分为5个100G,然后再把100G分为20个5G,那么当我们对着其中一个5G进行管理的思想,映射到其他块中,就形成了磁盘的分组管理。
这一块5G的磁盘中又分了好几个部分。
每一部分可以分出好几块区域 :
- Super Block: 存放文件系统本身的结构信息。记录的信息主要有:Data Block和inode的总量、未使用的Data Block和inode的数量、一个Data Block和inode的大小、最近一次挂载的时间、最近一次写入数据的时间、最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。
- **Group Descriptor Table:**块组描述符表,描述该分区当中块组的属性信息。
- Block Bitmap: 块位图当中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用。
- inode Bitmap: inode位图当中记录着每个inode是否空闲可用。
- inode Table: 存放文件属性,即每个文件的inode。
- Data Blocks: 存放文件内容。
由于Block Bitmap的存在,我们删除文件的时候会非常方便,这也是为什么我们删除一个文件非常快,而创建一个文件非常慢的原因。
软硬链接
示例
软硬链接的区别
软链接又叫符号链接,软链接相对于源文件来说是一个独立的文件,因此它有独立的inode编号并且大小并不随着原文件改变而改变,但是该文件只包含了源文件的路径名,所以软链接文件的大小要比源文件小得多。软链接就类似于Windows操作系统当中的快捷方式。
软链接的应用
我们可以在其他目录下去软链接别的目录的可执行程序,并且直接运行软链接即可使用该可执行程序。因此软链接又相当于我们Windows中的快捷方式。
硬链接数
硬链接相当于给我们的文件起了个别名,硬链接数代表了有几个文件的inode号相同,图中hard_link是test的硬链接,所以他们的inode号相同。
文件的三个时间
- Access:访问
- Modify:内容更改的时间。
- Change:属性被更改的时间。 内容的大小也是属性。
动静态库
所需要的.h文件和.c文件
my_add.h
#include<stdio.h>
int Add(int a,int b);
my_add.c
#include "my_add.h"
int Add(int a, int b)
{
printf("%d + %d = ?\n", a, b);
return a + b;
}
my_sub.h
#include<stdio.h>
int Sub(int a,int b);
my_sub.c
#include "my_sub.h"
int Sub(int a, int b)
{
printf("%d - %d = ?\n", a, b);
return a - b;
}
main.c
#include "my_add.h"
#include "my_sub.h"
int main()
{
int a = 10, b = 20;
int res = Sub(a, b);
printf("result: %d\n",res);
res = Add(a, b);
printf("result: %d\n",res);
return 0;
}
静态库的使用
我们使用my_add.c和my_sub.c生成的.o(可重定位二进制文件)进行打包(归档),打包后的文件就是我们所说的库。
ar -rc libmymath.a my_add.o my_sub.o 将目标文件打包为静态库
-r(replace):若静态库文件当中的目标文件有更新,则用新的目标文件替代旧的目标文件。
-c(create):建立静态库文件 my_add.o和my_sub.o打包生成了libmymath.a的在目录mylib下建立两个目录用于分别存放头文件和二进制(.o)打包好的库 mkdir -p mylib/include mkdir -p
mylib/lib分别把头文件和我们打包好的库放入我们提前创建好的目录下面 cp -f *.h mylib/include cp -f *.a
mylib/lib
以上操作可以放到一个Makefile文件中,这样能简化我们的操作。
将Makefile中的操作进行实现
使用gcc编译main.c
-
-I:指定头文件搜索路径。
-L:指定库文件搜索路径。
-l:指明需要链接库文件路径下的哪一个库。生成可执行程序后直接./可执行程序就可以得出运行结果
我们也可以把该头文件和库文件的路径拷贝到系统路径下,这样的话就不用再指明库文件和头文件了,但是我们的静态库还是要指明的,因为库很多,我们需要让gcc知道我们的库名(去掉前缀lib和后缀.a剩下的技术库名)。
动态库的使用
使用的文件与静态库中的一样,这里就不一一列举了。
1、使用-fPIC进行生成.o文件(这里生成.o文件的方式与静态库不同):
2、使用-shared选项为所有.o文件打包为动态库
3、将动态库和头文件分别放在mlb目录下边的两个目录中(include和lib)。
4、使用gcc编译main.c生成可执行程序。
5、由于动态库的特殊性,我们需要进行相应的操作才能使可执行程序可以运行起来。
法一:我们可以将.so文件拷贝到系统共享库路径下
法二:更改LD_LIBRARY_PATH
法三:配置/etc/ld.so.conf.d/
我们只对法一进行举例:
这样就可以运行了。