文件=文件内容+文件属性
笼统的讲磁盘是我们计算机中的一个机械设备(SSD等等除外)
磁盘写入的基本单位是:扇区
站在操作系统的角度,认为磁盘是线性结构的
磁盘大带来了管理成本的高,可以将磁盘进行分区,即大磁盘、小空间
每个单独的分区再写入文件系统
使用磁盘需要经历两个步骤:分区和格式化(写入文件系统)
Linux特有的EXT系列的文件系统

Boot Block:启动分区,保存于启动相关的内容
Block Group:文件系统会根据分区的大小划分为多个Block Group,每个Block Group都有着相同的结构组成
Super Block(超级块):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量、未使用的block和inode的数量、一个block和inode的大小、最近一次挂载的时间、最近一次写入数据的时间、最近一次检验磁盘的时间等其他文件系统的相关信息。如果Super Block的信息被破坏,可以说整个文件系统结构就被破坏了
Group Descriptor Table(GDT):块组描述符,描述块组属性信息
Block Bitmap(块位图):为一个二进制序列,从右向左,比特位的位置含义:block编号;比特位的内容含义:特定block是否被占用
inode Bitmap(inode位图):为一个二进制序列,从右向左,比特位的位置含义:inode编号;比特位的内容含义:特定inode是否被占用
inode Table:里面被分为一块一块的inode,用来存放文件的属性
Data blocks:里面被分为一块一块的block,用来存放文件的内容
在Linux中,文件名在系统层面没有意义,这是给用户使用的,Linux中真正的标识一个文件,是通过文件的inode编号,一个文件一个inode
inode里面会保存有int blocks[32];,与Data blocks相对应,这样拿到inode之后就能获取到文件的内容
注:
目录也是文件,同样也有inode和数据,目录的数据块内存放的是文件到inode编号的映射关系,因为我们创建的所有文件,全部都在一个特定的目录下
创建文件:
inode Bitmap找到空闲位置 -> 将文件属性导入到inode Table -> inode Bitmap找到空闲的位置 -> 与inode建立关系 -> 向Data blocks中写入 -> 在目录下建立该文件的inode与文件名的映射关系
查看文件的流程:
cat test.c -> 查看该文件所在目录对应的Data blocks -> 通过建立的映射关系查询到该文件名对应的inode -> 在inode Table找到对应的inode -> blocks[] -> 在Data blocks中找到对应的数据块 -> 打印文件内容
删文件速度快的原因:
只需要将inode Bitmap中该文件对应的比特位置0,再通过inode里面的blocks[]将Block Bitmap中使用到的数据块对应的比特位置0,后面有新的文件会覆盖inode Table和Data blocks的内容,因此这两个不需要修改
创建文件的整个流程:

存储属性
内核先找到一个空闲的i节点(这里是263466),内核把文件信息记录到其中
存储数据
该文件需要存储在三个磁盘块,内核找到了三个空闲块:300、500、800
将内核缓冲区的第一块数据复制到300,下一块复制到500,以此类推
记录分配情况
文件内容按顺序300、500、800存放,内核在inode上的磁盘分布区记录了上述块列表
添加文件名到目录
新的文件名abc,内核将入口(263466,abc)添加到目录文件,文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来
创建软链接
ln -s [文件名] [软链接文件的名字]

删除软链接
unlink [软链接文件的名字]
使用场景
类似于快捷方式,可以快速调用一个其它目录的可执行程序
软链接
软连接是有自己独立的inode的,软链接是一个独立的文件,有自己的inode属性,也有自己的数据块(保存的是指向文件的所在路径+文件名)
创建硬链接
ln [文件名] [硬链接文件的名字]

删除硬链接
直接使用rm
硬链接
硬链接本质根本就不是一个独立的文件,而是一个文件名和inode编号的映射关系,因为自己没有独立的inode
这个操作就相当于重命名了,删除源文件硬链接文件仍然可以使用

红色框出来的表示的是文件的硬链接数,表示有几个文件名与这个文件建立了映射关系
文件的inode结构体内有一个引用计数int ref;表示硬连接数,建立一个硬链接该值就会++,删除一个就会减少,当减为0的时候就表示该文件以及被删除了
创建的一个新目录的硬链接数为2

一个是目录本身还有一个是目录内部的.表示当前目录

如果在目录内部再新建一个目录,硬链接数变为了3

创建一个新目录之后,新目录内部还有一个..表示上级目录,就相当于又建立了一个硬链接指向dir


Access:文件最近被访问的时间
Modify:最近一次修改文件内容的时间
Change:最近一次修改文件属性的时间
当我们修改文件内容的时候,有可能修改文件的属性,如:文件的大小属性
在较新的Linux内核中,Access时间不会被立即更新,而是有一定的时间间隔,OS才会自动进行更新时间
Makefile如何判断make出来的文件已经是“is up to date”:编译形成的可执行程序的Modify时间比源文件的新
makefile与gcc会根据时间问题来判断源文件和可执行程序谁更新,从而指导系统哪些源文件需要被重新编译
ldd [可执行程序]:显示可执行程序依赖的库

一般库分为两种:动态库和静态库
在Linux中
库文件的命名:libXXX.so或者libYYY.a-…
库的真实名字:去掉lib前缀,去掉 .a-、.so-(包括)后缀,剩下的就是库名称
默认gcc动态链接编译,加上-static选项变为静态链接,生成的可执行文件会大很多
一套完整的库包括:库文件本身、头文件、说明文档(说明库中暴露出来的方法的基本使用方法)
将自己写的方法给别人用:
方案一:直接将源文件给别人
mytest.c 为别人写的主函数,在主函数内要调用我们的方法
obj=mytest.o add.o sub.o
mytest:$(obj)
gcc -o $@ $^
%.o:%.c
gcc -c $<
%.o:./test_lib/%.c
gcc -c $<
.PHONY:clean
clean:
rm -f *.o mytest

由此可见,只提供 .o 文件也可以进行链接
方案二:打包成静态库
将所有的 .o 打包形成的就是静态库,不需要源文件
libmymath.a:add.o sub.o
ar -rc $@ $^
%.o:%.c
gcc -c $<
.PHONY:clean
clean:
rm -rf *.o libmymath.a output
# 打包到一个文件夹进行发布
.PHONY:output
output:
mkdir output
cp -rf *.h output
cp libmymath.a output
# 安装到系统目录
.PHONY:install
install:
cp *.h /usr/include
cp libmymath.a /lib64


生成静态库:ar -rc libmymath.a add.o sub.o
ar是gnu归档工具,rc表示(replace and create)
查看静态库中的目录列表:ar -tv libmymath.a
t:列出静态库中的文件
v:verbose 详细信息
使用静态库进行编译:gcc mytest.c -I./lib -L./lib -lmymath -o mytest
mytest:mytest.c
gcc -o $@ $^ -I./lib -L./lib -lmymath
.PHONY:clean
clean:
rm -f mytest

-I:指明头文件搜索路径
-L:指明库文件搜索路径
-l:指明要链接哪一个库
之前使用库文件时不需要这些选项,是因为那些库都在系统的默认路径下:/lib64、/usr/lib、/usr/include等等,编译器是可以识别的
如果我们把对应的库和头文件拷贝到默认路径下,就可以不带这些选项,但非常不推荐
上面这个过程也是软件的安装过程
给别人用的其实就是一个库文件+一套头文件
方案二:打包成动态库
libmymath.so:add.o sub.o
gcc -shared -o $@ $^
# 产生.o目标文件,程序内部的地址方案是:与位置无关,库文件可以在内存的任意位置加载,而且不影响其他程序的关联性
%.o:%.c
gcc -fPIC -c $<
.PHONY:clean
clean:
rm -f libmymath.so *.o
.PHONY:lib
lib:
mkdir lib
cp *.h lib
cp libmymath.so lib

使用gcc -o mytest mytest -I./lib -L./lib -lmymath可以编译成功,但无法运行,有两种方法
运行时会使用加载器,来进一步告知系统我们的库在哪里

设置环境变量LD_LIBRARY_PATH:export LD_LIBRARY_PATH=[动态库所在文件夹路径]

系统配置文件:/etc/ld.so.conf.d/下新建一个[文件名].conf,将动态库的所在文件路径放进去,然后使用ldconfig刷新配置文件
如果只有动态库,是无法-static静态链接的,要想既可以动态链接又静态链接一般需要提供两个版本的库,如果都有且没有指明,gcc/g++会优先连接动态库