Linux之基础IO(下)

目录

缓冲区的概念

深入理解文件系统

创建文件的整个过程

软链接

硬链接


上一节课我们学习了基础IO中的文件的读写操作,以及文件描述符的概念和重定向的基本原理,本期我们继续进行基础IO的学习。

缓冲区的概念

在讲缓冲区之前,大家先看看下述代码。

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#include<string.h>int main()
{close(1);int fd=open("./log.txt",O_CREAT|O_WRONLY,0644);const char* msg="hello yjd\n";//通过write接口往1号文件描述符所指向的文件中写入数据write(1,msg,strlen(msg));//通过printf函数和fprintf函数往1号文件描述符所对应的文件中写入数据printf("%s",msg);fprintf(stdout,"%s",msg);return 0;
}

这段代码其实就是我们完成了一个输出重定向,将向显示器文件写的数据全部写到了文件中。

运行结果如下。

通过运行结果发现,我们确实将对应的字符串数据写入了log.txt这个文件中。

如果我们往代码中加入这一行代码会发生什么现象呢?

 

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#include<string.h>int main()
{close(1);int fd=open("./log.txt",O_CREAT|O_WRONLY,0644);const char* msg="hello yjd\n";//通过write接口往1号文件描述符所指向的文件中写入数据write(1,msg,strlen(msg));//通过printf函数和fprintf函数往1号文件描述符所对应的文件中写入数据printf("%s",msg);fprintf(stdout,"%s",msg);close(1);return 0;
}

我们往代码中加入了close(1)这行代码,我们再来看看运行结果。

运行结果如下。

 我么发现,为什么重定向的时候,只往log.txt中写入了一个字符串文件呢?按道理说应该是三个呀。这究竟是为什么?这就要学习我们今天的缓冲区的知识。我们以往用到printf函数和scanf这些函数,以及用到cin,cout这些流操作,我们通常认为要么是从键盘上获取数据,要么是往显示器打印数据。难道这些数据是直接写到相关硬件所对应的文件上去的吗?

之前我们讲到了一点,这些函数和流操作都是处于用户层的,用户层是无法向底层的硬件文件中写入数据的,用户层要往底层硬件写入数据,必须贯穿操作系统,那么这些流操作和函数是怎样把数据写入底层的文件的呢?用一个示意图为大家直观讲解。

示意图如下。

 

 我们使用的printf和fprintf函数都是往stdout标准输出流中进行数据写入。stdout的类型是FILE*类型,FILE*指向了一个结构体类型,这个结构体里封装了文件描述符和一个c语言缓冲区。所以我们可以形象的理解为stdout等等这些流都是一个用户缓冲区。我们首先将数据写入c语言缓冲区,然后再将c语言缓冲区中的数据刷新到文件内核缓冲区,然后再把文件缓冲区中的数据刷新到硬件设备文件中。

那么从c语言缓冲区刷新到文件内核缓冲区中的刷新策略是什么呢?

主要分为三种:

1.立即刷新(不缓冲)。

2.行刷新(行缓冲)。向显示器文件的内核缓冲区,就是行缓冲。

3.当缓冲区满了再进行刷新(全缓冲)。向普通文件的内核缓冲区,就是全缓冲。

一般情况下,全缓冲时,如果缓冲区没满,但是进程推出了,也会将缓冲区进行刷新。

 有了这些知识,对于刚开始的情景我们便可以进行解释。

重定向时,因为是往log.txt中进行数据的写入,log.txt是一个普通文件,所以它的刷新策略就是全缓冲,但是我们进行文件写入的时候,缓冲区没有写满,所以没有刷新,但是当我们进程退出时,c语言缓冲区的文件就刷新到了文件的内核缓冲区,最终写入了磁盘设备的log.txt文件中。

可是文件内核缓冲区怎么知道要往哪个文件进行刷新呢?

因为std是一个FILE*类型,其指向的结构体中存储了文件描述符,这个文件描述符,就是将来文件内核缓冲区要刷新的硬件文件目标。所以上述第二个代码我们关闭文件描述符之后,在进程退出时,c语言缓冲区中的数据并不会刷新到文件内核缓冲区,因为关闭了fd就不知道要往哪个文件里刷新,所以干脆不往文件内核缓冲区中进行刷新。但是write函数接口是一个系统调用接口,是直接往文件内核缓冲区中进行数据的写入的,文件内核缓冲区中的数据是会立即写入对应的文件的,所以,write函数的写入是不受close(fd)的影响的。

要close(fd)之后,继续刷新缓冲区中的文件,就要在close(fd)之前,加上fflush(stdout)的代码。

以上便就是文件缓冲区的概念。         

深入理解文件系统

在一个文件被打开时,我们为之创建了struct file类型的数据结构进行管理,当一个文件没有打开时,这个文件存储在哪里呢?这个文件是存储在磁盘上的。磁盘是什么呢?

要说磁盘是什么,我们得先了解一下硬盘。硬盘分为机械硬盘和固态硬盘。

机械硬盘的特点:便宜,使用周期长。重,速度慢。

固态硬盘的特点:速度快,便捷。贵,使用周期短。

 我们基于机械硬盘来了解文件系统。

上述结构中我们只需要关心盘片即可。盘片被分成了多个同心环,每一个换又被分成了多个扇区。一个扇区的大小为512Byte。

我们最终将整个盘面分为了一个有多个扇区组成的线性存储结构。一个磁盘的空间是很大的,为了方便进行管理,我们将磁盘进行了分区,比如我们电脑上常见的C,D,E,F盘。但是每个分区依旧是很大的,所以为了方便管理,我们又把每个分区分成了多个block块。

其中BOOT BLOCK中存放的就是系统启动的相关数据。Block group中存储相关的数据。但是此时每一个Block group依然很大,所以我们又要对每个Block group进行划分。

基于上图。

 Super Block:用于统计每个分区的所有的Block group的相关信息,比如使用了多少Inode,使用了多少Block等等。

Group Descriptor Table:用于统计当前组的相关信息,使用了多少了Inode,使用了多少Block块。

Block Bitmap:位图结构,用于统计数据块(Blocks)的使用情况,当前位为0为未被使用,为1为已经使用。

Inode Bitmap:位图结构,用于统计Inode块的使用情况。

Inode Table:里面为多个Inode块,inode块为一个结构体,每一个inode块都存储文件的相关属性数据。可以通过block数组定位数据块中所使用的数据块。

Data Blocks:里面有多个block块,用于存储文件的内容数据。 

看到上图大家可能会有疑惑,这个inode是什么呢?

作为用户,我们使用文件名辨别一个文件,但是操作系统并不是通过文件名来辨别文件,是通过一个叫inode的编号来辨别文件。可以这样理解,一个文件只有一个inode但是可以有多个文件名,所以操作系统用inode编号来辨别文件。

目录是文件吗?

通过上图我们可以看到,目录有它的属性,有它的inode编号,那么目录的Data Blocks里面存放什么数据呢?

目录的Data Blocks中存储的是文件的inode编号。当我们们创建一个文件时,操作系统会一起创建一个inode编号,这个inode编号被其当前目录所存储。

创建文件的流程

上述指令,操作系统底层是怎样执行的呢?

当创建一个文件时,操作系统同时会为这个文件分配一个inode编号,然后通过inode bitmap去查看没有被使用的inode块,找到之后,将当前文件的inode编号填入对应的inode块中,并且填入文件的先关属性数据,将当前inode块的位图置为1。

当对文件写入数据时,先在block bitmap中查找没有使用的数据块,找到之后,对这些数据块进行数据的写入,最终将这些数据块下标存储在inode块中的的block数组中。方便后续进行查找。

当查找一个文件时,先通过文件的inode编号查找到对应的inode块,然后通过里面的block数组找到对应的数据块,然后访问数据块中的数据。

软链接

创建软链接:ln -s 源文件名  链接名

我们发现运行软链接,也可以运行我们对应的可执行程序,所以这个软链接其实本质上就是一个快捷方式,与windows中的快捷方式相同。当我们的一个文件存储的位置比较深时,可以使用软链接的方式快速进行访问。

软连接的删除方式:unlink 连接名称

硬链接

硬链接的创建方式:ln 源文件名 链接名

我们发现,创建的硬链接也可以直接进行运行,难道它也是我们源文件的一个快捷方式吗?这不由得就产生了软链接和硬链接的区别。通过ll -i指令查看这两个链接的详细信息。

 我们发现软链接的inode编号与源文件不相同,但是硬链接的inode编号与源文件竟然出奇的相同,所以这便可以告诉我们答案,软链接是一个单独的文件,有自己的inode编号,软链接的data blocks里面存储的就是源文件的路径。硬链接不是一个单独的文件与源文件共享inode,是源文件的一个重命名。

 不知道大家之前有没有注意到属性那几列中的用彩色方框标记的这一列整数是什么含义呢?我们不妨再创建几个硬链接,然后再删除一个硬链接。

[yjd@hecs-87060 test7]$ ll
total 36
-rw-rw-r-- 1 yjd yjd    0 Jul 26 17:38 hello.c
-rw-r--r-- 1 yjd yjd   30 Jul 26 17:51 log.txt
-rw-rw-r-- 1 yjd yjd   58 Jul 26 11:36 makefile
-rwxrwxr-x 2 yjd yjd 8360 Jul 26 17:55 test
-rw-rw-r-- 1 yjd yjd  641 Jul 26 17:55 test.c
lrwxrwxrwx 1 yjd yjd    4 Jul 26 17:57 test_link -> test
-rwxrwxr-x 2 yjd yjd 8360 Jul 26 17:55 test_link_hard
[yjd@hecs-87060 test7]$ ln test  test_link_hard1
[yjd@hecs-87060 test7]$ ln test  test_link_hard2
[yjd@hecs-87060 test7]$ ll
total 60
-rw-rw-r-- 1 yjd yjd    0 Jul 26 17:38 hello.c
-rw-r--r-- 1 yjd yjd   30 Jul 26 17:51 log.txt
-rw-rw-r-- 1 yjd yjd   58 Jul 26 11:36 makefile
-rwxrwxr-x 4 yjd yjd 8360 Jul 26 17:55 test
-rw-rw-r-- 1 yjd yjd  641 Jul 26 17:55 test.c
lrwxrwxrwx 1 yjd yjd    4 Jul 26 17:57 test_link -> test
-rwxrwxr-x 4 yjd yjd 8360 Jul 26 17:55 test_link_hard
-rwxrwxr-x 4 yjd yjd 8360 Jul 26 17:55 test_link_hard1
-rwxrwxr-x 4 yjd yjd 8360 Jul 26 17:55 test_link_hard2
[yjd@hecs-87060 test7]$ ln test  test_link_hard3
[yjd@hecs-87060 test7]$ ll
total 72
-rw-rw-r-- 1 yjd yjd    0 Jul 26 17:38 hello.c
-rw-r--r-- 1 yjd yjd   30 Jul 26 17:51 log.txt
-rw-rw-r-- 1 yjd yjd   58 Jul 26 11:36 makefile
-rwxrwxr-x 5 yjd yjd 8360 Jul 26 17:55 test
-rw-rw-r-- 1 yjd yjd  641 Jul 26 17:55 test.c
lrwxrwxrwx 1 yjd yjd    4 Jul 26 17:57 test_link -> test
-rwxrwxr-x 5 yjd yjd 8360 Jul 26 17:55 test_link_hard
-rwxrwxr-x 5 yjd yjd 8360 Jul 26 17:55 test_link_hard1
-rwxrwxr-x 5 yjd yjd 8360 Jul 26 17:55 test_link_hard2
-rwxrwxr-x 5 yjd yjd 8360 Jul 26 17:55 test_link_hard3
[yjd@hecs-87060 test7]$ unlink  test_link_hard3
[yjd@hecs-87060 test7]$ ll
total 60
-rw-rw-r-- 1 yjd yjd    0 Jul 26 17:38 hello.c
-rw-r--r-- 1 yjd yjd   30 Jul 26 17:51 log.txt
-rw-rw-r-- 1 yjd yjd   58 Jul 26 11:36 makefile
-rwxrwxr-x 4 yjd yjd 8360 Jul 26 17:55 test
-rw-rw-r-- 1 yjd yjd  641 Jul 26 17:55 test.c
lrwxrwxrwx 1 yjd yjd    4 Jul 26 17:57 test_link -> test
-rwxrwxr-x 4 yjd yjd 8360 Jul 26 17:55 test_link_hard
-rwxrwxr-x 4 yjd yjd 8360 Jul 26 17:55 test_link_hard1
-rwxrwxr-x 4 yjd yjd 8360 Jul 26 17:55 test_link_hard2

通过上述代码不难发现,当我们在增加删除硬链接时,这一列的数组也会随之发生变化,其实这一列就表示当前文件的硬链接个数。当这个数子变成0时,就意味着当前文件没有了硬链接,也就意味着当前文件即将删除,所以就要把当前文件的inode块的位图置零。这其实就是刚开始我们在inode的那个结构体中设置的成员变量ref,也就是引用计数,当ref为零时,就意味着要删除当前文件,然后就要将当前inode块的位图置零。这也是在Linux中为什么删除一个文件比较快的原因。

好了以上便是linux中文件系统的所有内容。

本期内容到此结束^_^

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3268650.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Redis实战篇(黑马点评)笔记总结

一、配置前后端项目的初始环境 前端&#xff1a; 对前端项目在cmd中进行start nginx.exe&#xff0c;端口号为8080 后端&#xff1a; 配置mysql数据库的url 和 redis 的url 和 导入数据库数据 二、登录校验 基于Session的实现登录&#xff08;不推荐&#xff09; &#xf…

C++ - char*、const char*、char[]、string

const char* const char* 用来定义字符串常量。 char[ ] char型的字符数组是一种定长的数组&#xff0c;存储指定长度的字符序列&#xff0c;数组中的每个元素都是一个char类型的变量&#xff0c;如&#xff1a; char arr[] {h, a, l, l, o, \0}; char c arr[0]; // 访问…

使用 Windows 应用程序 SDK 构建下一代应用程序

微软面临的最大问题之一是如何让 Windows 再次成为吸引开发者的平台。无论用户使用什么设备和操作系统&#xff0c;都可以很容易地将 Web 前端放在支持桌面和移动用户的云原生应用程序上。 我们处在一个奇怪的境地&#xff0c;唯一能利用最新 PC 硬件的应用程序是 Office、Phot…

【中项第三版】系统集成项目管理工程师 | 第 11 章 规划过程组⑤ | 11.13 - 11.14

前言 第11章对应的内容选择题和案例分析都会进行考查&#xff0c;这一章节属于10大管理的内容&#xff0c;学习要以教材为准。本章上午题分值预计在15分。 目录 11.13 制定预算 11.13.1 主要输入 11.13.2 主要输出 11.14 规划质量管理 11.14.1 主要输入 11.14.2 主要工…

HTML前端面试题之<iframe>标签

面试题&#xff1a;iframe 标签的作用是什么?有哪些优缺点 ? 讲真&#xff0c;刷这道面试题之前我根本没有接触过iframe&#xff0c;网课没讲过&#xff0c;项目实战没用过&#xff0c;但却在面试题里出现了&#xff01;好吧&#xff0c;我只能说&#xff1a;前端路漫漫&…

数据挖掘-数据预处理

来自&#x1f96c;&#x1f436;程序员 Truraly | 田园 的博客&#xff0c;最新文章首发于&#xff1a;田园幻想乡 | 原文链接 | github &#xff08;欢迎关注&#xff09; 文章目录 3.3.1 数据的中心趋势平均数和加权平均数众数&#xff0c;中位数和均值描述数据的离散程度 &a…

快速搞定分布式RabbitMQ---RabbitMQ进阶与实战

本篇内容是本人精心整理&#xff1b;主要讲述RabbitMQ的核心特性&#xff1b;RabbitMQ的环境搭建与控制台的详解&#xff1b;RabbitMQ的核心API&#xff1b;RabbitMQ的高级特性;RabbitMQ集群的搭建&#xff1b;还会做RabbitMQ和Springboot的整合&#xff1b;内容会比较多&#…

火山引擎云搜索服务通过信通院向量数据库可信认证

7月16日&#xff0c;首届线下“可信数据库发展大会”在北京举办&#xff0c;会上中国信息通信研究院&#xff08;中国信通院&#xff09;公布了 2024 上半年“可信数据库”产品能力评测结果。火山引擎云搜索服务在基本功能、运维管理、安全性、兼容性、扩展性、高可用、工具生态…

【LeetCode 随笔】C++入门级,详细解答加注释,持续更新中。。。

文章目录 58.【简单】最后一个单词的长度&#x1f31f; &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f388;欢迎踏入我的博客世界&#xff0c;能与您在此邂逅&#xff0c;真是缘分使然&#xff01;&#x1f60a; &#x1f338;愿您在此停留的每一刻&#xff0c;都…

Html+Css网页开发之动态登录页面(默认Chrome)

>>效果展示图<< 一、需求分析与设计要求 实现了一个动态背景图案的效果&#xff0c;包括一个白色的容器&#xff0c;内部有一个标题、一个输入框、一个按钮和一些文本。 背景是一个渐变色的线性渐变&#xff0c;而在容器的周围&#xff0c;有一些随机的方形和圆形图…

Element快速学习

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;JavaWeb关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 什么是Element&#xff1f; Element&#xff1a;它是由饿了么团队开发的一个…

Dubbon-微服务通信(基本简介 基础实现)

目录 一、基本简介 二、基础实现 1. 提供统⼀业务api 2. 编辑服务提供者product 3. 编辑服务消费者order 4. 服务调⽤测试 一、基本简介 Dubbo是阿⾥巴巴开源的基于 Java 的⾼性能 RPC分布式服务框架&#xff0c;致⼒于提供⾼性能和透明化的RPC远程服务调⽤⽅案&…

springcloud使用openfegin进行服务调用

一、为什么需要使用Fegin 引言&#xff1a;在我们使用nacos的时候是不是也有一种服务调用的方法那个时候我们使用到RestTemplate去调用远程的服务&#xff0c;但是我们看下面的一个例子就可以知道RestTemplate这种方式对于维护和后期代码上来说是不合理的&#xff0c;以为会是…

【无标题】Git(仓库,分支,分支冲突)

Git 一种分布式版本控制系统&#xff0c;用于跟踪和管理代码的变更 一&#xff0e;Git的主要功能&#xff1a; 二&#xff0e;准备git机器 修改静态ip&#xff0c;主机名 三&#xff0e;git仓库的建立&#xff1a; 1.安装git [rootgit ~]# yum -y install git 2.创建一个…

针对datax-web 中Swagger UI接口未授权访问

application.yml 添加以下配置 实现访问doc.html 以及/v2/api-docs 接口时需要进行简单的校验 swagger:basic:enable: trueusername: adminpassword: 12345 配置重启后再进行相关访问则需要输入用户名和密码

【SQL 新手教程 2/20】关系模型 -- 主键

&#x1f497; 关系数据库建立在关系模型上⭐ 关系模型本质上就是若干个存储数据的二维表 记录 (Record)&#xff1a; 表的每一行称为记录&#xff08;Record&#xff09;&#xff0c;记录是一个逻辑意义上的数据 字段 (Column)&#xff1a;表的每一列称为字段&#xff08;Colu…

Footprint Analytics 助力 Core 区块链实现数据效率突破

Core 是一个基于比特币并兼容 EVM 的 Layer 1 区块链&#xff0c;正通过其创新解决方案引革新特币金融。作为首个引入非托管 BTC 质押协议及全球首个发行收益型 BTC ETP 产品的区块链&#xff0c;Core 站在了区块链技术的最前沿。通过利用超过 50% 的比特币挖矿哈希算力&#x…

Java高频面试题分享

文章目录 1. 策略模式怎么控制策略的选取1.1 追问&#xff1a;如果有100种策略呢&#xff1f;1.2 追问&#xff1a;什么情况下初始化Map 2. 什么是索引&#xff1f;什么时候用索引&#xff1f;2.1 追问&#xff1a;怎么判断系统什么时候用量比较少2.2 追问&#xff1a;如何实时…

R下载包显示unable to access index for repository:.......无法打开URL

1、报错“Warning: unable to access index for repository https://mirrors.bfsu.edu.cn/CRAN/src/contrib: cannot open URL https://mirrors.bfsu.edu.cn/CRAN/src/contrib/PACKAGES” 解决方法&#xff1a; > options(reposhttp://cran.rstudio.com/) #把https换成htt…

在树莓派上安装 ROS Melodic

树莓派的支持的系统比较多&#xff0c;以 Raspbian Buster 为例&#xff0c;记录在树莓派上下载并构建 ROS Melodic 的步骤&#xff0c;其他的派类似。 一、安装 ROS Melodic 打开树莓派终端并执行以下步骤。 1. 安装 repository key $ sudo sh -c echo "deb http://pack…