1.前言
1.铺垫
a.文件=内容+属性
b.访问文件之前,都得先打开,修改文件,都是通过执行代码的方式完成修改,文件必须被加载到内存中
c.谁打开文件?进程在打开文件
d.一个进程可以打开多少个文件呢?可以打开多个文件
e.进程和文件的关系,struct task_struct 和struct XXXX?
f.系统中是不是所有的文件都被进程打开了?不是!没有被打开的文件?就在磁盘中
一定时间段内,系统中存在多个进程,也可能同时存在更多的被打开的文件,OS要不要管理多个被进程打开的文件呢?肯定的,如何管理呢?先描述,再组织!预言一下:内核中一定要有描述被打开文件的结构体,并用其定义对象。
2.C语言文件接口-对比重定向
以“w”方式打开文件,文件会被自动清空
以“a”追加形式写入
什么叫做当前路径:进程在启动时会自动记录自己启动时所在的路径。
程序默认打开的文件流:stdin,stdout,stderr可以直接被使用。
extern FILE *stdin/stdout/stderr:FILE是C语言自己封装的一个结构体,必定要封装特定的fd。
访问文件不仅仅有C语言的文件接口,OS必须提供对应的访问文件的系统调用。
int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_t mode);
w:清空文件---int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
a:追加文件---int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
C语言的文件接口实际上就是封装了系统调用!
3.文件fd
为什么访问文件,用系统调用接口,都必须使用fd呢?文件描述符的本质,就是数组下标。
ssize_t write(int fd,const void *buf,size_t count);
ssize_t read(int fd,const void *buf,size_t count);
int close(int fd);
每打开一个文件,创建一个struct_file存入文件描述符表,通过不同的fd找到每一个file结构体(属性,方法集,缓冲区),文件关闭时存入磁盘中。
如何理解一切皆文件,每个设备的操作方法一定是不一样的,为了屏蔽硬件的差异统一管理,就像C++中的多态概念一样,在上层通过统一的方法,实现操作不同的硬件。
文件fd的分配规则:最小的没有被使用的数组下标,会分配给最新打开的文件
4.缓冲区问题
缓冲区它就是一块内存区域,用空间来换时间。
为什么要有?提高使用者的效率:聚集数据,一次拷贝(刷新),提高整体效率
我们一直在说的缓冲区和内核中的缓冲区,没关系(尽管他有),是语言层面的缓冲区,C语言自带缓冲区。
调用系统调用是又成本的,时间&&空间,有效的减少C接口的使用效率。
1.无刷新,无缓冲
2.行刷新---显示器,XXX\nYYY
3.全缓冲,全部刷新---普通文件,缓冲区被写满,才刷新
a.强制刷新
b.进程退出的时候,要自动刷新
具体在哪里?缓冲区是被FILE结构来维护的!一个文件维护一个缓冲区
如何证明?如果向显示器进行打印,刷新方案就是行,对test.txt刷新策略,立即变成了全缓冲,刷新数据,就是清空缓冲区,修改数据的一种方式。
2.文件系统
系统中是不是所有得文件都被打开了呢?大部分文件都是没有被打开的。
如果没有被打开呢?在哪里保存呢?磁盘,SSD,OS要不要管理一下磁盘上的文件呢?如何让OS快速的定位一个文件
1.磁盘的物理存储
磁盘/柱面:唯一的编号
扇区(编号):是磁盘IO的基本单位---不一定是系统和磁盘IO的基本单位
磁头,盘面:都有唯一编号
如果我想访问磁盘中一个扇区:
通过磁头定位:磁道/柱面 cylinder
使用哪一个磁头:head
哪一个扇区:Sector
CHS定位法,那么任何文件,不就是多个扇区承载的数据吗?
2.磁盘的逻辑存储
对磁盘的管理变成了对数组的增删查改!
Sector:扇区
sector/单盘扇区的=0
sector%单盘扇区的个数=temp
temp/一个磁道上的扇区的个数==我在哪一个磁道
temp%一个磁道上的扇区的个数==结果,我是特定一个磁道的哪一个扇区
OS认为,一次和磁盘IO一个扇区(512)单位太小了,IO的基本单位为4KB
Linux磁盘文件特性:文件=内容+属性
内容和属性分开存储,内容的大小不确定,可能很大,可能很小,属性是固定大小的,只不过每个类别内容不一样。
系统中,标识一个文件,用的不直接是文件名,而是inode
- i节点表:存放文件属性如文件大小,所有者,最近修改时间等inode table
- inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。(比特位的位置:第几个inode,比特位的内容:表示该inode是否被使用)
- 数据区:存放文件内容
- 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用。(比特位的位置:表示的是块号,比特位的内容:对应的块是否被使用)
- Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成
- 超级块(Super Block):存放文件系统本身的结构信息,记录的信息主要有Block和inode的总量,未使用的Block和inode的数量,一个Block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息,Super Block的信息被破坏,可以说整个文件系统的结构就被破坏了。
文件名呢?任何一个普通文件,一定在一个目录中,目录是不是文件?是,inode+目录的内容(文件名和inode的映射关系)
对一个文件,进行增删改查,都和该文件所处的目录有关系
查找一个文件,在内核中,都要逆向的递归得到,从根目录进行路径解析
一个被写入文件系统的分区,要被Linux使用,必须要先把这个具有文件系统的分区进行“挂载”。
一个文件系统所对应的分区,挂载在对应的目录中,分区的访问,都是通过所挂载的路径访问的!
访问一个文件,可以根据路径前缀,优先分出文件在哪一个分区下
3.软硬链接
硬链接本质就是在指定的目录下,插入新的文件名和目标文件的映射关系,并让inode的引用计数++,软链接本质就是一个独立文件,软链接内容里面放的目标文件的路径。
1.硬链接
硬链接是文件数据块的一个引用,它指向了文件在磁盘上的实际数据块。一个文件可以有多个硬链接,这些链接共享相同的数据块。当创建一个文件的硬链接时,实际上只是在文件系统的inode表中为现有的数据块增加了一个引用计数。
特性:
- 硬链接和源文件指向相同的数据块。
- 删除硬链接不会影响源文件或其他硬链接。
- 硬链接不能跨文件系统或目录。
- 不能对目录创建硬链接(除了特殊的
.
和..
目录项)。 - 硬链接的创建和删除只影响inode的链接计数。
2.软链接
软链接是一个特殊的文件,它包含了对另一个文件或目录的引用(路径)。与硬链接不同,软链接实际上是一个新文件,只是这个文件的内容是另一个文件或目录的路径。
特性:
- 软链接的内容是另一个文件或目录的路径。
- 删除源文件会导致软链接变为“死链接”或“断链”。
- 软链接可以跨文件系统或目录。
- 可以对目录创建软链接。
- 可以通过
ln -s
命令创建软链接。
# 创建file1
echo "Hello, World!" > file1
# 创建硬链接
ln file1 hardlink1
# 创建软链接
ln -s file1 symlink1
# 查看file1的硬链接数(默认至少为2,因为还有.和..目录项)
ls -li file1
# 通过硬链接和软链接访问文件内容
cat hardlink1
cat symlink1
# 删除file1
rm file1
# 硬链接hardlink1仍然可以访问(因为数据块还在)
cat hardlink1
# 软链接symlink1现在变为死链接(因为源文件已删除)
cat symlink1 # 将显示错误信息