文章目录
1.文件系统
我们使用ls -l的时候看到的除了看到文件名,还看到了文件元数据。
每行包含7列:
模式
硬链接数
文件所有者
组
大小
最后修改时间
文件名
ls -l读取存储在磁盘上的文件信息,然后显示出来
除了通过这种方式来读取,还有一个stat命令能够看到更多信息:
上面的执行结果有几个信息需要解释
1.1 inode
为了能解释清楚inode我们先简单了解一下文件系统
Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的。
Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子。
超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。SuperBlock的信息被破坏,可以说整个文件系统结构就被破坏了 。
GDT,Group Descriptor Table:块组描述符,描述块组属性信息。
块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用。
inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
i节点表:存放文件属性 如文件大小,所有者,最近修改时间等。
数据区:存放文件内容。
将属性和数据分开存放的想法看起来很简单,但实际上是如何工作的呢?我们通过touch一个新文件来看看如何工作。
为了说明问题,我们将上图简化:
创建一个新文件主要有一下4个操作:
- 存储属性
内核先找到一个空闲的i节点(这里是1314297)。内核把文件信息记录到其中。 - 存储数据
该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第一块数据
复制到300,下一块复制到500,以此类推。 - 记录分配情况
文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。 - 添加文件名到目录
新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(1314297,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。
1.2 硬链接
定义
定义:硬链接是文件系统中一个文件的目录入口。它直接指向文件的物理位置(inode),而不是文件名。
特点
硬链接可以链接到目录之外的任何文件。
硬链接不能跨文件系统创建。
删除一个文件的硬链接并不会删除文件本身,直到文件的最后一个硬链接被删除。
硬链接不能链接到目录(因为目录本身也是文件,但出于安全考虑,Linux不允许这样做)。
硬链接之间完全等价,对任何一个硬链接的修改都会反映到所有硬链接上。
使用方法
# 创建一个硬链接
ln [源文件名] [目标文件名]
# 示例
ln file1.txt file1_hardlink.txt
abc和def的链接状态完全相同,他们被称为指向文件的硬链接。内核记录了这个连接数,inode 1314299 的硬连接数为2。
我们在删除文件时干了两件事情:1.在目录中将对应的记录删除,2.将硬连接数-1,如果为0,则将对应的磁盘释放。
1.3软链接
定义
定义:软链接类似于Windows中的快捷方式,它包含了对另一个文件或目录的引用(路径)。
特点
可以链接到文件或目录。
可以跨文件系统创建。
删除软链接本身并不会删除被链接的文件或目录。
如果软链接的目标文件或目录被删除或移动,软链接将失效(变为“死链接”)。
软链接可以有自己的权限和属性。
使用方法
# 创建一个软链接
ln -s [源文件或目录路径] [目标软链接名]
# 示例
ln -s /path/to/original_file.txt link_to_original.txt
2.动态库和静态库
2.1动态库
2.11定义与特点
定义:动态库是在程序运行时被加载到内存中的库文件,它包含了在多个应用程序中可共享的代码和数据。动态库的文件名通常以.so(Shared Object,共享对象)作为后缀。
特点:
节省空间:由于多个程序可以共享同一个动态库,因此可以显著减少磁盘空间的使用。
便于更新:当动态库更新时,只需要替换库文件,而不需要重新编译或重新链接使用这些库的程序。
运行时加载:动态库在程序运行时被加载,这可能会稍微增加程序的启动时间,因为需要动态地解析和加载库中的函数和数据。
2.12使用方法
在编译时,使用-L选项指定动态库所在的目录,使用-l选项指定动态库的名称(不包括前缀lib和后缀.so)。
运行时,系统会根据/etc/ld.so.conf文件、/etc/ld.so.conf.d/目录下的配置文件或LD_LIBRARY_PATH环境变量指定的目录来查找动态库。
2.2 静态库
2.21定义与特点
定义:静态库是在程序编译时被链接到目标代码中的库文件,它会被复制到可执行程序中,每个程序都有自己的副本。静态库的文件名通常以.a(Archive,归档文件)作为后缀。
特点:
不共享:每个使用静态库的程序都会有一份库文件的副本,因此会占用更多的磁盘空间。
独立运行:由于静态库被嵌入到程序中,因此程序可以独立运行,不需要额外的库文件支持。
更新不便:当静态库更新时,需要重新编译所有使用这些库的程序。
2.22 使用方法
在编译时,同样使用-L选项指定静态库所在的目录,使用-l选项指定静态库的名称(不包括前缀lib和后缀.a)。但是,由于静态库在编译时就被链接到程序中,因此不需要在运行时额外指定库的路径。
2.3示例
2.31编写库代码
libexample.h
#ifndef LIBEXAMPLE_H
#define LIBEXAMPLE_H
void hello_from_lib(void);
#endif
libexample.c
#include <stdio.h>
#include "libexample.h"
void hello_from_lib(void) {
printf("Hello from the library!\n");
}
2.32编译生成动态库
gcc -fPIC -shared -o libexample.so libexample.c
这里,-fPIC 表示生成位置无关代码(Position Independent Code),这对于动态库是必须的;-shared 表示生成共享库(即动态库)。
2.33 编译生成静态库
在生成静态库之前,我们需要先编译 libexample.c 为对象文件(.o 文件):
gcc -c libexample.c -o libexample.o
然后再使用 ar 命令将对象文件打包成静态库。
ar rcs libexample.a libexample.o
2.4总结
1.静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。
2.动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
3.一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。
4.在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)。
5.动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。