操作系统:浅谈文件系统

目录

1.理解文件系统

1.1.从磁盘开始的抽象存储结构

​编辑

1.2.操作系统下的文件管理

1.2.1.知识储备

1.2.2.存储文件的属性

1.2.3.存储文件的内容

1.2.4.如何新建文件

1.2.5.如何理解目录 

1.2.6.如何找到某一个文件

1.3.操作系统如何打开文件 

2.软硬链接


我们知道文件可以分为:已被打开文件(被进程加载) 和 未被打开文件(在磁盘中保存)这两种文件,而我们对文件的学习也不能只局限于 对被进程打开的文件,因为大部分文件都不是被打开的,而是在磁盘中。这就引申到了操作系统是如何管理未被打开文件,并如何将他们从磁盘中加载到内存,并被进程调用的呢?这就是我们接下来要讲的文件系统的知识了

1.理解文件系统

我们知道文件未被打开时是存储在磁盘这个硬件中,当我们研究文件在磁盘中存储的问题,再结合操作系统的本质就是不断地抽象出数据结构,再连接这些结构。我们学习的核心就是了解操作系统是如何在磁盘中对文件进行增删查改的!

1.1.从磁盘开始的抽象存储结构

如图为磁盘的物理结构和俯视图

从这里我们能够知道:

  • 磁盘俯视来看就是一个圆,而这个圆中会截取一定宽度的圆环称为一个磁道,而这个磁道再均分成一块一块的扇区
  • 磁盘存储时是以“块”为单位的(从扇区体现),扇区是磁盘进行IO读写的最小基本单元,一般是512字节
  • 对于磁盘来说,通过转换“南北极”来实现数据0,1的写入

接着我们来谈谈磁盘是如何定位数据到文件的呢

这里我们就知道了,后续操作系统进行软硬件连接时需要考虑CHS这三个数据!!!

值得说的是:我们通过读写 磁头的编号 就能找到对应的磁盘,再通过 磁头的位置 找到磁道,再结合 磁盘转到的位置 我们就能够定位到任何一个扇区

讲完宏观的结构,接下来我们抽象出一段圆环

接着我们对于这个块的研究等价于对这个圆环(磁盘的一段磁道,若干个扇区)的研究,同时这个抽象图又和我们平常使用的数组这个结构十分类似,那么最终对磁盘的研究就可以从数组这个数据结构作为载体出发了。

做一道数学题

这个也就是CHS定位法的核心,这样子我们通过计算就验证了可以通过数组这个结构在磁盘中抽象出这么一个文件存储的载体。有兴趣可以写一下这个查找程序,so easy的

1.2.操作系统下的文件管理

1.2.1.知识储备

操作系统按照扇区为单位进行存取,也可以基于文件系统按照文件块为单位进行存取,因为一个扇区的大小为512个字节,由于大小依然很小,可能会存在多次的IO调用,浪费系统资源,实际上操作系统定义一个文件块为8个扇区,大小为4096字节,略大于4kb(后面我们统一认为大小为4kb)

实际使用时,我们通过LBA转化成CHS地址,进而定位写入磁盘,在底层对磁盘的写入,变成了在操作系统层面上对一个一个 文件块 的数组的增删查改

注意:磁盘中一个块对应一个扇区,操作系统中一个文件块对应8个扇区 


介绍完了一些基本知识,我们来看看操作系统是如何进行文件管理的!!!

如图:操作系统为了便于管理,在自己内部将对应磁盘大小分为若干个区,再把区划分为组,加下来通过抽象组这个载体来管理文件块这个基本单位。

接下来我们开始学习如何进行 块组 的管理!

先介绍一下概念

  • Boot Block:启动块,作为分区的头,包含磁盘的信息,和操作系统的启动信息
  • Block group:作为管理文件块的载体

  • Super Block:存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量, 未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的 时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个 文件系统结构就被破坏了

不一定每个块组都有,一般是若干个块组共用一个,管理整个分区,作为操作系统对分区的管理描述的结构体对象,一个分区多个保存防止系统丢失数据


  • inode Table:存放文件属性 如 文件大小,所有者,最近修改时间等

实际上就是存放inode的结构体数组

  • inode Bitmap:每个bit表示一个inode编号是否空闲可用。

用比特位的0、1表示某一个inode编号是否被使用,一个文件块4096字节,而存放32000个inode编号的一个位图大小4KB(4000字节),所以一个文件块能通过位图表示inode编号。

  • Block Bitmap:记录Data Block中哪个数据块已经被占用,哪个数据块没 有被占用

  • Group Descriptor Table:块组描述符,描述块组属性信息,管理一个块组
  • Data Block:存放文件内容

我们知道 文件 = 内容 + 属性,在我们写入文件内容前,需要先写入文件管理数据给磁盘,例如磁盘进行分区后,需要记录这个分区的相关数据再进行文件的内容的写入。也就是块组的引入本质上是为了解决文件内容和属性存储问题。

文件的内容和属性一般是分开存储的,存在块组的不同区域


1.2.2.存储文件的属性

往Linux系统中输入指令 ls -li 我们发现 最前面会有一个数字,这个数字叫做 inode 编号

  • 一般情况下,一个文件只有一个inode,基本上每个文件都有一个inode。
  • 在不同的分区中,inode的数据是唯一的,识别文件只与inode有关
  • inode是用来保存文件的属性,本质上是一个结构体
  • inode中存储的文件属性的种类是固定的

 注意inode不等于inode编号,并且大小固定为128字节

struct inode
{
    // 文件大小 权限 拥有者...

    // inode编号
    // Block block[15]
}

在inode Table中,inode编号便于通过相对位置来找到文件,本质上就是一个存储inode的数据结构

struct inode inode_table[N]    // 可以视为inode结构体数组

1.2.3.存储文件的内容

Data Block是一个以4KB为单位的一块巨大的文件内容存储区,存放整个块组所有文件的内容,在这个区域中我们也是通过编号来进行访问的。存储规则是:通过Block Bitmap查找哪一个数据块没有被占用,然后存储数据进去,接着通过inode结构体中的block数组中存放索引下标(映射),并向这些数组中存放文件内容。

实际操作系统中,0-12下标的数据块是直接映射进数据库保存文件的内容,13间接映射,里面保存更多的 块列表 来进行二次索引,三次索引.......这样实现大文件存放在若干个4KB中保存 

当一个文件特别大时,会在多个块组中存储,实现跨组访问,inode编号在分区里不变即可

1.2.4.如何新建文件

核心就是查询两个位图,找到两个数据,进而实现文件的搭建

  • 先查inode Bitmap查询位图,找到最近的一个没有被使用的比特位由0置为1,然后查询遍历位图时的偏移量,加载进inode,设置文件属性和编号
  • 接着从block Bitmap里面找到一个位置,同理0置为1,记录偏移量,然后从inode中的Block block找到对应的block然后写入文件的内容

那我们如何删除呢?

我们在新建文件时,就已经知道文件的inode编号,我们可以找到对应的位图中的比特位,由1改为0,同理把占用的块也由1置0,未被释放的资源后续可能被其他文件覆盖。

1.2.5.如何理解目录 

实际使用计算机时,面向用户的是文件名而不是inode,也就是inode是实现内核与文件的映射,又因为Linux中一切皆文件。那么我们知道 目录 本质上也是文件,也有自己的inode结构体,那么目录的块存放的数据是什么呢?

目录的块中存放着 文件名 和 inode的映射关系(k-v关系),也就是我们通过文件名可以找到目录下文件的inode进而连接整个文件管理体系,所以同一个目录下不允许存在同名文件。又inode在该分区中独一无二,所以文件名和inode互为k-v关系。

讲到这里,顺便提一下:文件名不是inode结构体的内容,而是目录的内容。

1.2.6.如何找到某一个文件

  1. 找到文件的上一级目录,在通过访问文件的block存储的数据找到文件名和inode的映射关系这样就能找到 inode和inode编号
  2. 接着通过inode编号找到哪个组,进而访问到哪个块,然后获取文件的属性、内容

那么如何找到上一级的目录呢(也就是找到他的inode)?那上一级的目录的目录如何找到呢?也就是回归到 我们需要找到根目录的inode。找到文件需要从根目录开始逐层查找到该文件的上一级文件。查找时我们也是借助进程,那么就会有cwd,进行会记录当前的路径


关于查找不同分区下的文件,因为Linux在进行磁盘格式化分区后,会进行挂载,并且可以通过文件的路径来找到挂载对应的分区,也就是我们可以通过文件路径来确定在哪个分区。

1.3.操作系统如何打开文件 

  • 未被打开前,文件存在于磁盘,打开时,操作系统创建进程来打开这个文件
  • 进程拥有自己的cwd通过路径来定位在磁盘的哪一个分区,接着顺着路径向下找
  • 找到创建inode结构体,实现了文件属性的写入
  • 接着通过inode编号找到Data Block,就可以写入文件的内容
  • 将缓冲区的内容拷贝进文件的对应Block block数组对应的数据块

2.软硬链接

建立软连接的指令

ln -s 待链接文件名 软连接文件名
// 例如
ln -s log.txt log.sort.link

创建软连接时,log.sort.link具有自己的inode,也就是创建的软连接是一个新文件 

建立硬链接的指令

ln 待链接文件名 硬链接文件名
// 例如
ln file.txt file.hard.link

file.hard.link没有自己的inode(和源文件一致),也就是硬链接不是独立的文件

 我们可以通过 ls -li查看inode、权限、硬链接数、拥有者....... 

注意:可以给目录建立软连接,不允许给目录建立硬链接。


软连接

在Windows中软连接的体现就是:文件的快捷方式,软连接的本质就是指向源文件的一个副本文件。

软连接形成一个副本文件便于用户使用,也防止对源文件进行非法的操作,比如有人想要故意删除一个文件,那么软连接就可以迷惑他……


硬链接

硬链接不是一个独立的文件,本质是指定目录内部的一组关于 文件名 和 inode 的映射关系!

我们知道文件被删除的本质:没有了当前文件名和inode的映射关系,在文件系统层面,inode结构体中定义了一个引用计数变量,标明有几个文件名的映射关系,也就是有几个硬链接

当我们分别创建一个新文件和新的目录时我们发现,硬链接数分别为1和2,因为普通文件只有一组文件名和inode的映射关系,目录文件有两组映射关系。

因为我们创建目录时,目录内会自动创建两个文件 . 和 .. 文件,其中 . 文件为指向这个目录的映射,而目录名本身跟自己的inode也有一组映射关系,所以是两个,那么假如我们在这个目录下在创建一个目录后原目录下的硬链接数变为几了呢?(可以通过ls -lia指令查看)

  • 22
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
管理系统操作日志是指在管理系统中记录用户操作行为的一种记录方式,可以用来跟踪用户的操作行为,监控系统的运行情况,以及追查系统中出现的问题。 在设计管理系统操作日志时,需要考虑以下几点: 1. 记录内容:需要记录哪些用户操作行为?一般来说,需要记录用户的登录、登出、新增、修改、删除等操作。 2. 记录格式:操作日志应该采用什么格式进行记录?可以考虑采用JSON格式进行记录,方便日后的数据处理和分析。 3. 存储位置:操作日志应该存储在哪里?可以考虑将操作日志存储在数据库中,或者存储在文件中。 4. 记录方式:操作日志应该如何记录?可以考虑通过代码编写,在关键业务逻辑处添加日志记录代码,或者通过AOP(面向切面编程)的方式进行记录。 以下是一个操作日志类的示例代码: ```java public class OperationLog { // 用户名 private String username; // 操作时间 private String operateTime; // 操作内容 private String operateContent; // 操作结果 private String operateResult; public OperationLog(String username, String operateTime, String operateContent, String operateResult) { this.username = username; this.operateTime = operateTime; this.operateContent = operateContent; this.operateResult = operateResult; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getOperateTime() { return operateTime; } public void setOperateTime(String operateTime) { this.operateTime = operateTime; } public String getOperateContent() { return operateContent; } public void setOperateContent(String operateContent) { this.operateContent = operateContent; } public String getOperateResult() { return operateResult; } public void setOperateResult(String operateResult) { this.operateResult = operateResult; } } ``` 该类中包含了操作日志需要记录的基本信息,包括用户名、操作时间、操作内容和操作结果等。在系统中进行关键操作时,可以通过该类进行操作日志的记录。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值