当前位置: 首页 > news >正文

如果表不存在则创建_当创建一个文件的时候,操作系统发生了什么

操作文件是我们平时经常有的操作。但是我们可能并不是很了解他们原理,比如为什么删除一个很大的文件,会非常快?创建一个文件的时候,系统发生了什么?为什么删除的文件,还可以恢复?知其然知其所以然。我们一起深入探索文件系统的一些原理。这篇先分析一下创建文件的过程。

我们先看一下文件系统在硬盘中的布局。

ab59412ed2dc989119dac8a221b09379.png

我们再看一下文件系统在内存中的布局。

032a585e0f8a6501bbca9cebd4b4b069.png

对着上面的图,从左向右,我们看到

1 一个进程有一个文件描述符数组,这个描述符数组的元素,就是我们平时操作文件的时候,使用的那个fd。定义如下:

struct file * filp[NR_OPEN];

2 每个文件描述符只是索引,他对应的项指向一个file结构体,file结构体定义如下。

// 管理打开文件的内存属性的结构,比如操作位置(inode没有读取操作位置这个概念,),实现系统进程共享inode
struct file {
    unsigned short f_mode;
    unsigned short f_flags;
    unsigned short f_count;
    struct m_inode * f_inode;
    off_t f_pos;
};

file结构体是和inode的作用是不一样的,inode是更多的是存储文件的一些持久化的数据,比如大小,时间、属主,数据块位置等。inode是存在硬盘中的。在操作的文件的时候才会加载到内存。如果有修改,需要回写硬盘。file存储的是文件临时的元数据,他只存在内存里。比如一个文件当前读写位置,打开模式等等。关闭文件后就会丢失这些数据。

3 在文件系统中,每一个文件都对应一个inode结构体。inode保存了一个文件的元数据,包括大小,时间,属主,块号等等。inode存在于硬盘和内存,内存的inode叫m_inode,他的部分属性和硬盘inode一一对应(硬盘inode叫d_inode),还有一些是只存在内存中的属性。我们看一下inode在硬盘中的布局。

3b278226a8eb694511ca2685f9a4a409.png

了解一系列结构体后,我们开始分析创建文件的这个过程。主要是两件事情,第一,判断文件是否存在,如果不存在则开始创建。

1 根据路径找到最后一级目录对应的inode节点。目录其实也是文件,他和一般文件的区别是,一般文件存储的是用户数据,目录文件存储的是文件信息。目录文件里存储的数据就是一个对象数组,每个元素保存了文件名和inode节点号。

// 目录项结构
struct dir_entry {
    // inode号
    unsigned short inode;
    // 文件名
    char name[NAME_LEN];
};

假设我们找/a/b/hello.txt这个文件。因为/是根文件系统的根路径,他在文件系统初始化的时候,根文件系统会从固定的位置(第一个inode节点),把他对应的inode结构体加载到内存中。我们根据根inode,就知道根目录下面有多少dir_entry,然后逐个比较找到目录a对应的dir_entry,从dir_entry中得到目录a的inode号,再根据a的inode号把inode结构体从硬盘中加载到内存,继续这个过程,直到最后找到hello.txt。

2 所以我们从一个目录下找一个目录或者文件的时候,其实就是遍历这个数组,对比name是否一样,是的话根据inode号取出inode结构体,从而取得文件数据。

3 因为我们是创建文件,所以是肯定找不到的。

4 上面已经解释过,一个文件对应一个inode。现在我们创建一个文件,那自然,我们就要先在硬盘中申请一个inode,并且修改文件系统的元数据inode位图,即这个inode被使用了。然后再在内存中申请一个m_inode。供用户操作文件的。至此,创建文件就完成了。我们发现,创建一个文件,底层发生的事情其实就是在硬盘申请一个inode就可以了。

5 当我们开始操作m_inode对应的文件的时候。比如写入。回归上面的inode结构体可以发现,这时候文件其实是没有被分配硬盘空间的。现在需要写入,那首先就要先在硬盘中申请一块空间。并修改块位图信息。然后申请一块和该硬盘块关联的内存块,用户写入的数据就存在该内存块中,系统会定时回写到硬盘中对应的块。

这就是创建一个文件的大致过程。

相关文章:

  • 胖终端和瘦终端的区别_企业级无线覆盖与家庭级无线覆盖的区别与发展趋势
  • pythonnode js结合_Node js 和 python 混合编程之JSON入参的区别 如何转换js对象使其能在python脚本中作为python 字典直接使用...
  • sql 统计每月入职离职人数_说离职就离职,他们就不害怕失业吗,为什么90后的离职率那么高...
  • redis 端口_基础架构之Redis
  • python check module_Python 的 module 机制(重要)
  • springboot技术架构图_阿里技术专家告诉你:如何画出优秀的架构图
  • python嗅探m3u8_python通过m3u8下载视频
  • 安装python3.6.1的步骤_在Linux上安装Python3.6.1
  • python单词按字典序输出_python – 我可以通过匹配键作为前缀在字典中保留新单词...
  • 后台页面需要设置登录过期时间吗_电商后台优惠券设计
  • 机械制图符号_机械图纸感觉每一个都很复杂,这12个机械制图的简化画法,你会吗...
  • python爬虫基础教程115_清华学姐推荐的Python视频115集,拿走不谢 .
  • python测试udp端口_python检测远程udp端口是否打开的方法
  • 图像条纹检测 python_预告:面向强反射表面的多传感器三维检测技术研究
  • 高德地图标记文字修改样式_地图标注有哪些优势?如何进行地图标注?
  • ----------
  • SegmentFault for Android 3.0 发布
  • Docker下部署自己的LNMP工作环境
  • Javascripit类型转换比较那点事儿,双等号(==)
  • Linux后台研发超实用命令总结
  • Map集合、散列表、红黑树介绍
  • Spring Boot MyBatis配置多种数据库
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • Vue 重置组件到初始状态
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 关于字符编码你应该知道的事情
  • 观察者模式实现非直接耦合
  • 讲清楚之javascript作用域
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 前端攻城师
  • 如何胜任知名企业的商业数据分析师?
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 白色的风信子
  • C# - 为值类型重定义相等性
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • ###C语言程序设计-----C语言学习(3)#
  • #define用法
  • #laravel 通过手动安装依赖PHPExcel#
  • #QT(TCP网络编程-服务端)
  • (175)FPGA门控时钟技术
  • (23)Linux的软硬连接
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (八)Spring源码解析:Spring MVC
  • (超详细)语音信号处理之特征提取
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (排序详解之 堆排序)
  • (四) 虚拟摄像头vivi体验
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • .dwp和.webpart的区别
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .net 使用ajax控件后如何调用前端脚本