标签搜索

目 录CONTENT

文章目录

文件系统.md

小小城
2021-08-22 / 0 评论 / 0 点赞 / 6 阅读 / 4,616 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-02,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

文件系统

@[toc]

一、FILE

1.因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访问的。

所以C库当中的FILE结构体内部,必定封装了fd

#include <stdio.h>
#include <string.h>

int main()
{
	const char *msg0="hello printf\n";
	const char *msg1="hello fwrite\n";
	const char *msg2="hello write\n";
	printf("%s", msg0);
	fwrite(msg1, strlen(msg0), 1, stdout);
	write(1, msg2, strlen(msg2));
	fork();
	return 0;
}

运行结果:
在这里插入图片描述
但是如果给输出重定向一下:
在这里插入图片描述
我们发现 printf 和 fwrite (库函数)都输出了2次,而 write 只输出了一次(系统调用)。为什么呢?肯定和fork有关

  1. 一般C库函数写入文件时是全缓冲的,而写入显示器是行缓
  2. printf fwrite 库函数会自带缓冲区,当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。
  3. 而我们放在缓冲区中的数据,就不会被立即刷新,甚至fork之后,但是进程退出之后,会统一刷新,写入文件当中。
  4. 但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的一份数据,随即产生两份数据。
  5. write 没有变化,说明系统调用没有所谓的缓冲,子进程拷贝时,缓冲区中已经没有内容了,所以 只打印一份

综上: printf和 fwrite 库函数会自带缓冲区,而 write 系统调用没有带缓冲区

另外,我们这里所说的缓冲区,都是用户级缓冲区。其实为了提升整机性能,OS也会提供相关内核级缓冲区,不过不再我们讨论范围之内。

那这个缓冲区谁提供呢? printf fwrite 是库函数, write 是系统调用,库函数在系统调用的“上层”, 是对系统调用的“封装”,但是 write 没有缓冲区,而 printf fwrite 有,足以说明,该缓冲区是二次加上的,又因为是C,所以由C标准库提供

注意:缓冲区是存在于文件流指针的结构体当中:

二、理解文件系统

  •  1.文件的存储结构如下:

在这里插入图片描述

  •  Linux正统的文件系统(如ext2、ext3)一个文件由目录项、inode和数据块组成。**
  • 目录项:包括文件名和inode节点号。
  • Inode:又称文件索引节点,是文件基本信息的存放地和数据块指针存放地。
  • 数据块:文件的具体内容存放地。
  •  Linux正统的文件系统(如ext2、3等)将硬盘分区时会划分出目录块、inode Table区块和data block数据区域。
  •  一个文件由一个目录项、inode和数据区域块组成
  •  Inode包含文件的属性(如读写属性、owner等,以及指向数据块的指针),数据区域块则是文件内容。
  •  当查看某个文件时,会先从inode table中查出文件属性及数据存放点,再从数据块中读取数据。
  • 目录项的结构:

在这里插入图片描述

  • inode结构:

在这里插入图片描述

  •  2.创建一个文件的步骤:
  • 我们从前面可以知道文件的内容和属性是分开存放的,那么又是如何管理它们的呢?现在我们以创建一个文件为例来讲解。
  • 在命令行输入命令:
$ who > userlist
  • 当完成这个命令时。文件系统中增加了一个存放命令who输出内容的新文件userlist,那么这整个过程到底是怎么回事呢?
  • 文件主要有属性、内容以及文件名三项。内核将文件内容存放在数据区,文件属性存放在i-节点,文件名存放在目录 中。

创建成功一个文件主要有以下四个步骤:

  1. 存储属性 也就是文件属性的存储,内核先找到一块空的i-节点。

例如,内核找到i-节点号921130。内核把文件的信息记录其中。如文件的大小、文件所有者、和创建时间等。

  1. 存储数据 即文件内容的存储,由于该文件需要3个数据块。因此内核从自由块的列表中找到3个自由块。

如600、200、992,内核缓冲区的第一块数据复制到块600,第二和第三分别复制到922和600.

  1. 记录分配情况,数据保存到了三个数据块中。所以必须要记录起来,以后再找到正确的数据。分配情况记录在文件的i-节点中的磁盘序号列表里。

这3个编号分别放在最开始的3个位置。

  • 添加文件名到目录,新文件的名字是userlist 内核将文件的入口(47,userlist)添加到目录文件里。文件名和i-节点号之间的对应关系将文件名和文件和文件的内容属性连接起来,找到文件名就找到文件的i-节点号,通过i-节点号就能找到文件的属性和内容。
  •  3.创建一个目录的过程:
  • 前面说了创建一个文件的大概过程,也了解文件内容、属性以及入口的保存方式,那么创建一个目录时又是怎么回事呢?
  • 我现在test目录使用命令mkdir 新增一个子目录child:
  • 从用户的角度看,目录child是目录test的一个子目录,那么在系统中这层关系是怎么实现的呢?实际上test目录包含一个指向子目录child的i-节点的链接,原理跟普通文件一样,因为目录也是文件。

目录其实也是文件,只是它的内容比较特殊。所以它的创建过程和文件创建过程一样,只是第二步写的内容不同。

  1. 系统找到空闲的i-节点号887220,写入目录的属性
  2. 找到空闲的数据块1002来存储目录的内容,只是目录的内容比较特殊,包含文件名字列表,

列表一般包含两个部分:i-节点号和文件名,这个列表其实也就是文件的入口,新建的目录至少包含三个目录”.”和”..”其中”.”指向自己,”..”指向上级目录,我们可以通过比较对应的i-节点号来验证,887270
对应着上级目录中的child对应的i-节点号

  1. 记录分配情况。这个和创建文件完全一样
  2. 添加目录的入口到父目录,即在父目录中的child入口。

一般都说文件存放在某个目录中,其实目录中存入的只是文件在i-节点表的入口,而文件的内容则存储在数据区。我们一般会说“文件userlist在目录test中”,其实这意味着目录test中有一个指向i-节点921130的链接,这个链接所附加的文件名为userlist,这也可以这样理解:目录包含的是文件的引用,每个引用被称为链接。文件的内容存储在数据块。文件的属性被记录在一个被称为i-节点的结构中。I-节点的编号和文件名关联起来存在目录中。

三、理解链接:

  •  我们知道文件都有文件名与数据,这在 Linux 上被分成两个部分:用户数据 (user data) 与元数据(metadata)。
  •  用户数据,即文件数据块 (data block),数据块是记录文件真实内容的地方
  •  **而元数据则是文件的附加属性,**如文件大小、创建时间、所有者等信息。
  •  在 Linux 中,元数据中的 inode 号(inode 是文件元数据的一部分但其并不包含文件名,inode 号即索引节点号)才是文件的唯一标识而非文件名。
  •  文件名仅是为了方便人们的记忆和使用,系统或程序通过 inode 号寻找正确的文件数据块。

下图展示了程序通过文件名获取文件内容的过程。
在这里插入图片描述

  •  为解决文件的共享使用,Linux 系统引入了两种链接:硬链接 (hard link) 与软链接(又称符号链接,即soft link 或 symbolic link)。
  •  不仅为Linux 系统解决了文件的共享使用,还带来了隐藏文件路径、增加权限安全及节省存储等好处
  •  1.硬链接:
  • 若一个 inode 号对应多个文件名,则称这些文件为硬链接。换言之,硬链接就是同一个文件使用了多个别名(hard link 就是 file 的一个别名,他们有共同的 inode)。

在这里插入图片描述

  • 硬链接可由命令 link 或 ln 创建。如下是对文件 oldfile 创建硬链接
link oldfile newfile
ln oldfile newfile

由于硬链接是有着相同 inode 号仅文件名不同的文件,因此硬链接存在以下几点特性:

  • 文件有相同的 inode 及 data block;

  • 只能对已存在的文件进行创建;

  • 不能交叉文件系统进行硬链接的创建

  • 不能对目录进行创建,只可对文件创建

  • 删除一个硬链接文件并不影响其他有相同 inode 号的文件

  •  2.软连接

  • 实际上只是一段文字,里面包含着它所指向的文件的名字,系统看到软链接后自动跳到对应的文件位置处进行处理;

  • 相反,硬链接为文件开设一个新的目录项,硬链接与文件原有的名字是平权的,在Linux看来它们是等价的。

  • 由于这个原因,硬链接不能连接两个不同文件系统上的文件。

由于软链接是有着自己的 inode 号文件名不同的文件,因此软链接存在以下几点特性:

  • 文件有不同的 inode 及 data block;

  • 能对已存在的文件进行创建;

  • 能交叉文件系统进行硬链接的创建

  • 能对目录进行创建

  • 删除一个软链接文件并不影响源文件

  • 软链接可由命令 ln 创建。如下是对文件 oldfile 创建软链接

ln -s oldfile newfile
  •  3.区分软硬链接
软连接硬链接
软连接与windows下的快捷方式类似,你把dir1/file1硬连接到dir2/file2, 就是在dir2下建立一个dir1/file1的镜像文件file2,它与file1是占用一样大的空间的,并且改动两者中的一个,另一个也会发生同样的改动.
通过记录源文件的路径进而访问到源文件的数据,是一个单独的文件,有独立的inode号,相当于快捷方式自己和源文件没有任何区别,通过相同的inode号,访问文件的数据,相当于把数据拷贝一份再重命名一次
删除源文件,软连接文件直接失效硬链接文件只是把链接数减1,直到源文件的连接数减为0,那么才删除源文件成功
软连接问价可以跨分区建立,也可以对目录进行创建硬链接文件不能跨分区,不能对目录进行创建

四、动态库和静态库

  •  1.区分静态库和动态库
静态库(.a)动态库(.so)
程序在编译连接的时候把代码连接到可执行文件中,程序运行的时候不再需要静态库程序在运行时才去链接动态库的代码,多个程序共享使用动态库的代码
把一些.O文件打包成特殊的二进制程序,自身不能执行,可以和其他的.C /.CPP文件一起生成可执行文件,这就是静态连接库把.C /.CPP文件编译成一种特殊的二进制程序,自身不能执行,但可以和其他可执行程序使用,这就是动态链接库
静态库就像是搬家,走到哪里就把家中的所有东西拿着动态库就是走到哪里,缺什么就在哪里买
  •  注意⚠️:
  • 1.一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址,而不是外部函数所在目标文件的整个机器码,所以就导致静态文件远大于动态文件
  • 2.动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间
  • 操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间
  •  2.生成动态库和静态库的方法:

a.生成动态库:(动态库的命名规则:lib名称.so)

第一步:gcc -fPIC -c xxx.c -o xxx.o
第二部:gcc -shared xxx.o -o libxxx.so

b.生成静态库
第一步:gcc -c xxx.c -o xxx.o
第二部:ar -cr libxxx.a xxx.o

0

评论区