Linux中的缓冲区和文件系统详解

2025-03-21 02:50

本文主要是介绍Linux中的缓冲区和文件系统详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Linux中的缓冲区和文件系统详解》:本文主要介绍Linux中的缓冲区和文件系统方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教...

一、FILE结构

1、fd

FILE是在C中封装起来的一个结构体,那我们访问文件的时候都是通过fd访问的,自然在FILE中是封装了fd的,FILE结构体中,int _file存放的就是fd,其他的成员基本都是与缓冲区有关的

Linux中的缓冲区和文件系统详解

2、缓冲区

(一)有换行有return全部打印

看下面一段代码:

Linux中的缓冲区和文件系统详解

Linux中的缓冲区和文件系统详解

(二)无换行无repythonturn的C接口打印

很显然的,我们打印出了所有我们需要的内容,我们再看下一段

Linux中的缓冲区和文件系统详解

Linux中的缓冲区和文件系统详解

理想状态下我们应该是打印出结果后然后进行while一直循环,实际上是一只不会打印,这是为什么呢?是的,待在缓冲区里

首先我们要知道,缓冲区的大概位置,我们上面贴了一张FILE结构体的结构图,我们可以很www.chinasem.cn清楚地看到缓冲区是FILE的成员指针指向的一块位置,也就是说缓冲区一定在用户空间而不是内核空间

Linux中的缓冲区和文件系统详解

(三)无换行无return的系统调用接口打印

我们在调用上面三个函数的时候,都是调用的C接口,自然都待在缓冲区里了,我们再看编程下一个程序

Linux中的缓冲区和文件系统详解

Linux中的缓冲区和文件系统详解

在这个程序中我们直接调用系统调用接口write,所以它不会经过C语言的缓冲区,而是直接打印

(四)有换行无return的C接口打印

我们再来看一组程序

Linux中的缓冲区和文件系统详解

Linux中的缓冲区和文件系统详解

这个程序和(二)程序的区别就只有换行,这告诉我们,C语言缓冲区对于显式器是行缓冲的,C语言标准库的文件流有三种缓冲模式,分别是全缓冲、行缓冲和无缓冲

  • 全缓冲 _IOFBF :通常用于对磁盘文件的操作,数据会先被存储在缓冲区中,直到缓冲区被填满或者调用 fflush 函数、关闭文件(fclose)时,才会将缓冲区中的数据写入实际的文件,在全缓冲模式下,不会因为遇到换行符而自动刷新缓冲区
  • 行缓冲 _IOLBF :常见于标准输入、标准输出等终端设备相关的流,当遇到换行符(\n)时,会自动刷新缓冲区,将缓冲区中的数据写入对应的设备或文件,某些情况下即使没有换行符,缓冲区满时也会刷新
  • 无缓冲 _IONBF :标准错误输出通常默认是无缓冲的,确保错误信息能够立即显示,在无缓冲模式下,数据会立即写入对应的设备或文件,不会进行缓冲,因此不存在行刷新的概念

(五)无换行有return的C接口打印

Linux中的缓冲区和文件系统详解

Linux中的缓冲区和文件系统详解

Linux中的缓冲区和文件系统详解

进程退出return的时候,也会对缓冲区进行刷新

(六)深入理解缓冲区在用户空间

Linux中的缓冲区和文件系统详解

Linux中的缓冲区和文件系统详解

Linux中的缓冲区和文件系统详解

我们打印在显示器上的内容和打印在文件中的内容不一致,只有write打印了一遍,其他是按照顺序打印了两遍,我们当然能看出来这是fork的锅,接下来我们就深入理解谈一谈缓冲区

首先我们分析第一张结果图,因为显示器是行缓冲的,所以我们C接口的打印放到缓冲区中一行就会被打印到屏幕上一行,三条语句执行完之后缓冲区是空的,然后write再往上写,所以整个打印出来的顺序也是按照代码中来的

然后我们分析最后一张图,第一个我们可以肯定的是,打印到文件一定不是行缓冲,那就更不是无缓冲,实际上,由于文件是在存储硬件当中的,由于我们的效率问题,对于这种存储类的缓冲条件都是全缓冲,把缓冲区塞满再写入存储硬件中比塞一点写一点效率高得多,所以前三句C接口调用的打印全部在缓冲区中,然后write将自己打印,然后我们就碰到了fork,创建子进程,父子进程此时共享代码段和数据段,因为它们都没有做修改,然后我们就碰到了return 0,前面我们提到:进程结束也是要清空缓冲区的,此时父或子进程某一个先结束(由调度器决定),其中一个进程清空缓冲区的行为会引起另一个进程的写实拷贝,此时我们就有两份缓冲区,两个进程都结束都要清空缓冲区,自然在缓冲区中的内容要打印两份了(在这里要注意了,不只是子进程修改数据会引起子进程的写时拷贝,父进程对数据做修改时父进程也要发生写时拷贝,被写时拷贝的数据再再发生修改就直接修改了,不发生写实拷贝

二、文件系统

文件一般存储在硬盘当中,我们已经学习了动态的文件,也就是进程打开文件访问文件的过程,现在我们来学习一下静态的文件,我们来直接学习一下固态硬盘

1、固态硬盘

固态硬盘是一种基于NAND闪存的存储单元,我们常用的笔记本上的固态硬盘存储单元类型一般都是TLC的,三层单元,每个单元存储3bits,寿命较短成本较低,它通过电荷存储数据,通过高低电平区分0/1

NAND闪存的写入操作只能在已擦除的块上进行,擦除的最小单位就是块,通常为128KB-4MB,写入的最小单位是页,通常为4KB,所以它读的速度特别快,可以到微秒级,因为需要先擦除块,写的速度较慢,只能到毫秒级,每个块的擦写次数有限,超过后就会失效,一般TLC的擦鞋上限在500-1500次

这样的性质会带来一些不太好的结果,比如我们要写的内容很小,假设为4KB,那么我们先要擦除高达4MB的块才能进行写入,所以我们通过算法,将写入分散到所有块,避免某些块因为多次擦除而失效

固态硬盘控制器中的核心逻辑叫做FTL ( Flash Translation Layer ) Flash翻译层,负责将文件系统的逻辑地址映射到物理地址,是不是有点像进程地址通过页表映射到物理地址呢

接下来我们要学习文件系统的逻辑地址LBA,因为我们很清楚FTL映射到物理地址的过程是与页表映射是相似的,而逻辑地址的组织方式与进程地China编程址可是不同的,虽然是有相似之处的~

2、逻辑地址LBA

LBA 从 0 开始,按照连续的整数顺序依次为存储设备中的每个数据块编号,存储设备中的每个数据块都对应一个唯一的 LBA 值,比如第一个数据块的 LBA 是 0,第二个是 1,依此类推,我们对应的数据块有Super Block、Group Descriptor Table、Block Bitmap、inode Bitmap、inode Table、Data blocks六个,最理想的情况下它们的LBA按照我上面写的顺序从0到5

我们把一块固态硬盘,我们笔记本上有一些品牌比如说某L开头的品牌,在我们购买的时候是默认给你带1T固态的,一般的品牌就是512G,我们拿到笔记本之后会对电脑进行分区,C盘作为系统盘分到最多的内存,G盘作为游戏盘给到300多G,然后D盘用来学习写代码,留个200G,EF盘用来存一些其他的东西,这样一套流程下来我们就分好盘了,我们说对硬盘做管理当然也是先描述后组织,Block Group就是组织和管理磁盘空间的一种重要结构

Linux中的缓冲区和文件系统详解

在n个Bjslock Group之前有一个叫做Boot Block(引导块)的区域,在计算机启动过程中起着至关重要的作用,它是计算机启动过程的起点,没有引导块中的引导代码,计算机就无法知道如何加载操作系统,也就无法正常启动

我们按照知识理解易难顺序倒着往前来说

(一)数据块 Data Blocks

用来存储数据的块,NAND FLASH 内部的数据块由多个page组成,通常大小为4KB(现在也有8KB和16KB),这个page就是我们前面提到的最小写入单位:页

Linux中的缓冲区和文件系统详解

(二)inode表 inode Table

inode全称为索引节点,是一种数据结构,用于存储单个文件的全部属性,一般来说每个文件都有一个inode

struct inode
{
	//inode编号
	//文件类型
	//权限
	//引用计数
	//拥有者
	//所属组
	
    // 直接块指针
    unsigned long i_block[NUM];
    // 一次间接块指针
    unsigned long i_ind_block;
    // 二次间接块指针
    unsigned long i_dind_block;
    // 三次间接块指针
    unsigned long i_tind_block;
}

其中inode编号每个文件都是不同的,我们主要说说数据块指针

(1)直接块指针

直接块指针的NUM一般是12,它指向的位置是我们可以直接用来存储的位置,如果我们内容比较小(12*4KB = 48KB以内),那么直接块指针可以直接访问这些数据

(2)一次间接块指针

如果内容大于48KB,就需要一次间接块指针,一次间接块指针指向一个间接块,这个间接块存储中存储着多个指向数据块的指针,如我们的内容在(4KB/4b)*4KB = 4MB以内,通过一次间接块指针和直接块指针就可以访问这些数据

(3)二次间接块指针

二次间接块指针指向一个二次间接块,这个二次间接块存储中存储着多个指向间接块的指针,与一次间接块指针类似,这样我们存储的范围就达到了(4KB/4b)*(4KB/4b)*4KB = 4GB

(4)三次间接块指针

同上,最终我们最大的存储范围达到了 (4KB/4b)*(4KB/4b)*(4KB/4b)*4KB = 4TB

Linux中的缓冲区和文件系统详解

(三)inode位图 inode Bitmap

我们通过位图来和inode一一对应,位图上对应的比特位为0,那么该inode就没有被使用,可以被分配,如果为1则被占用,当从1变为0时,该inode又可以被分配了,其实这个过程就是一个删除的过程,一旦一个文件的inode无了,那么这文件是真的无了

在文件系统中,标识文件不是看它的名字,而是看它的inode,一旦inode和文件取消绑定了,那么操作系统就找不到这个文件了,再次写入其他内容的时候也就会被擦除覆盖了,换而言之,删除恒等于可以被覆盖

(四)块位图 Block Bitmap

我们通过位图来和数据块page一一对应,位图上对应的比特位为0,那么该页page就没有被使用,可以被分配,如果为1则被占用,当从1变为0时,该page又可以被分配了,如果我们要删除一块空间,只需要将它的对应的位置0,到再次被写入的时候就会消失了,当然我们的NAND闪存是定期擦除的,过一段时间它自己就被擦除了

Linux中的缓冲区和文件系统详解

(五)块组描述符表 Group Descriptor Table

记录了该块组的详细信息,包括块位图的位置、inode 位图的位置、inode 表的起始位置等,用于定位和管理块组内的各种数据结构

(六)超级块 Super Block

超级块是文件系统的核心,记录了文件系统的全局信息,如块大小、inode 数量、空闲块数量等,为了防止超级块损坏导致文件系统无法使用,每个块组中可能会包含超级块的副本,不过并非所有块组都有

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程China编程(www.chinasem.cn)。

这篇关于Linux中的缓冲区和文件系统详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153864

相关文章

基于Spring实现自定义错误信息返回详解

《基于Spring实现自定义错误信息返回详解》这篇文章主要为大家详细介绍了如何基于Spring实现自定义错误信息返回效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录背景目标实现产出背景Spring 提供了 @RestConChina编程trollerAdvice 用来实现 HTT

一文详解SQL Server如何跟踪自动统计信息更新

《一文详解SQLServer如何跟踪自动统计信息更新》SQLServer数据库中,我们都清楚统计信息对于优化器来说非常重要,所以本文就来和大家简单聊一聊SQLServer如何跟踪自动统计信息更新吧... SQL Server数据库中,我们都清楚统计信息对于优化器来说非常重要。一般情况下,我们会开启"自动更新

kotlin中的数据转换方法(示例详解)

《kotlin中的数据转换方法(示例详解)》这篇文章介绍了Kotlin中将数字转换为字符串和字符串转换为数字的多种方法,包括使用`toString()`、字符串模板、格式化字符串、处理可空类型等,同时... 目录1. 直接使用 toString() 方法2. 字符串模板(自动转换)3. 格式化字符串(控制输

Linux系统中配置静态IP地址的详细步骤

《Linux系统中配置静态IP地址的详细步骤》本文详细介绍了在Linux系统中配置静态IP地址的五个步骤,包括打开终端、编辑网络配置文件、配置IP地址、保存并重启网络服务,这对于系统管理员和新手都极具... 目录步骤一:打开终端步骤二:编辑网络配置文件步骤三:配置静态IP地址步骤四:保存并关闭文件步骤五:重

Linux进程终止的N种方式详解

《Linux进程终止的N种方式详解》进程终止是操作系统中,进程的一个重要阶段,他标志着进程生命周期的结束,下面小编为大家整理了一些常见的Linux进程终止方式,大家可以根据需求选择... 目录前言一、进程终止的概念二、进程终止的场景三、进程终止的实现3.1 程序退出码3.2 运行完毕结果正常3.3 运行完毕

Linux命名管道方式

《Linux命名管道方式》:本文主要介绍Linux命名管道方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、命名管道1、与匿名管道的关系2、工作原理3、系统调用接口4、实现两个进程间通信二、可变参数列表总结一、命名管道1、与匿名管道的关系命名管道由mkf

Java实现XML与JSON的互相转换详解

《Java实现XML与JSON的互相转换详解》这篇文章主要为大家详细介绍了如何使用Java实现XML与JSON的互相转换,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. XML转jsON1.1 代码目的1.2 代码实现2. JSON转XML3. JSON转XML并输出成指定的

python中time模块的常用方法及应用详解

《python中time模块的常用方法及应用详解》在Python开发中,时间处理是绕不开的刚需场景,从性能计时到定时任务,从日志记录到数据同步,时间模块始终是开发者最得力的工具之一,本文将通过真实案例... 目录一、时间基石:time.time()典型场景:程序性能分析进阶技巧:结合上下文管理器实现自动计时

Linux文件名修改方法大全

《Linux文件名修改方法大全》在Linux系统中,文件名修改是一个常见且重要的操作,文件名修改可以更好地管理文件和文件夹,使其更具可读性和有序性,本文将介绍三种在Linux系统下常用的文件名修改方法... 目录一、引言二、使用mv命令修改文件名三、使用rename命令修改文件名四、mv命令和rename命

利用Python和C++解析gltf文件的示例详解

《利用Python和C++解析gltf文件的示例详解》gltf,全称是GLTransmissionFormat,是一种开放的3D文件格式,Python和C++是两个非常强大的工具,下面我们就来看看如何... 目录什么是gltf文件选择语言的原因安装必要的库解析gltf文件的步骤1. 读取gltf文件2. 提