Linux_文件系统
假定外部存储设备为磁盘,文件如果没有被使用,那么它静静躺在磁盘上,如果它被使用,则文件将被加载进内存中。故此,可以将文件分为内存文件和磁盘文件。
- 内存文件
- 磁盘文件
- 软、硬链接
一.内存文件
1.1 c语言的文件接口
- fopen:FILE *fopen(const char *path, const char *mode);
- mode:
- r :读方式
- w:写,打开即清空文件
- a:追加方式
- mode:
- fclose:int fclose(FILE *fp);
- fwrite:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
- fgets:char *fgets(char *s, int size, FILE *stream);
- fputs:int fputs(const char *s, FILE *stream);
- snprintf:int snprintf(char *str, size_t size, const char *format, …);
1.2 系统接口
1.2.1 open
- 返回值:返回一个文件描述符(下文讨论)
- pathname:指定文件路径
- flags:位图,可以用宏来指定打开方式
- O_RDONLY:读方式
- O_WRONLY: 写方式
- O_CREAT: 不存在则创建
- O_TRUNC: 打开后会清空文件
- O_APPEND:追加方式打开,不清空文件
- mode :指定创建文件时的起始权限
// 1.读时的open写法
int fd = open("log.txt", O_RDONLY);// 2.清空写时的open写法
int fd1 = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC);//3.追加写时的open写法
int fd2 = open("log.txt", O_WRONLY | O_CREAT | O_APPEND);
当一个进程要打开文件时,操作系统将文件的属性加载到内存中,根据这些属性创建一个struct file
结构体,并且将该结构体与进程控制块task_struct
建立联系。
1.2.2 close
- fd : 文件描述符,open返回值。
1.2.3 write
- count:写入字节数
1.2.4 read
1.3 文件描述符-file descriptor
操作系统将文件加载进内存,创建对应的struct file 结构体,并且与struct task_struct
建立联系。在Linux中,task_struct 内部有一个 struct files_struct
字段,这个结构体里面有struct file* fd_array[]
数组,file descriptor就是这个数组的下标。如图:
1.3.2 文件描述符本质
文件描述符的本质就是struct file*fd_array 数组中的下标,当操作系统创建文件结构体struct file
时,将该结构体地址填入数组中,至此进程与文件建立了联系。
-
操作系统从开始扫描数组,遇到空位置,则填入地址,给调用进程返回数组下标,即文件描述符。
观察上面代码,发现文件描述符是从3开始的,这是因为c语言中默认打开三个文件,标准输入-stdin,标准输出-stdout,标准错误-stderr,它们对应数组的 0 1 2,stdout和stderr默认都指向显示器。
1.4 struct file 与 struct FILE
struct file是内核级别的结构体,而struct FILE是c语言库中定义的结构体,这两者之间没有任何关系。
struct FILE内部有一个文件描述符int fd;
字段。当进程读写文件时,os会根据文件描述符找到对应的struct file
结构体,然后进行读写操作。
1.5 重定向
重定向有三种:输出重定向,追加重定向,输入重定向
- 输出重定向:我们可以在命令行中输入命令
ls . > text
,这样原本打印在显示器上的消息就打印到文本text中了,这叫做输出重定向。 - 追加重定向:输出重定向会先清空文件,然后写入内容,追加重定向不清空文件,在文件末尾追加内容
- 输入重定向:在命令行中输入
cat < text
,原本是从键盘读取字符,然后重定向到从text中读取字符 ,这就是输入重定向。
为什么ls . > text
可以将打印到显示器上的数据打印到text中的呢?在Linux中,命令ls
是一个程序,它也是用c语言编写的,所以是用printf来进行打印的,而printf默认会打印到stdout对应的文件中,stdout中的fd为1,如果我们将数组下标为1的元素内容从显示器改变为目标文件,那么这样就做到了将打印到显示器上的数据打印到text中。输入重定向也是同理,改变文件描述符的指向即可。即:重定向的原理就是改变数组元素的指向。这种改变是上层无法获知的,所以stdout依旧认为它对应的文件是显示器。
1.5.1 重定向的三种方式
- 命令行
./test > text 2>&1
: 将test的执行结果输出到text中,并且将1号文件描述符的内容靠别到2号文件描述符中,即,stderr也会输出到text中./test 1>log 2>err
:将标准输出改变为log,标准错误改变为err
- dup2(int oldfd, int newfd);
- 例如dup2(3, 2); 将3号文件描述符的内容拷贝到2号文件描述符中
- 先关闭1号文件描述符,然后调用open
close(1);
int fd = open("log.txt", O_WRONLY|O_CREAT|_TRUNC); // 1
1.6 内核级缓冲区和用户级缓冲区
c语言库中struct FILE
结构体中有一个缓冲区,用来暂存数据,这个缓冲区叫做用户级缓冲区。内核结构体struct file
中有一个缓冲区,用来暂存数据,这个缓冲区叫做内核级缓冲区。缓冲区的目的是为了提高IO效率。
用户级缓冲区的刷新策略:‘
- 无缓冲
- 行缓冲(显示器) :遇到换行符将数据刷新到内核级缓冲区
- 全缓存(普通文件):当缓冲区满了才将数据刷新到内核级缓冲区
内核级缓冲区的刷新策略由os系统决定,当然我们可以调用fsync()
强制刷新。
1.6.1 数据流动方式
当程序调用printf函数时,先将字符串拷贝到用户缓冲区,然后结合相关刷新策略,调用write函数将字符串从用户缓冲区拷贝到内核缓冲区,最后os结合刷新策略将数据刷新到外设中,这就是数据的流动方式。共经历三次拷贝。
1.6.2 代码示例-缓冲区
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>int main()
{// 情况1printf("hello world!\n");// 情况2 printf("hello world!");const char* msg = "tieite\n"; write(1,msg, strlen(msg)), fork();return 0;
}
- 情况1:输出结果:
- 情况2:输出结果:
为什么会有这样奇怪的结果呢?这与缓冲区的刷新策略有关?因为printf默认输出到显示器,而显示器的刷新策略是行刷新,所以情况1正确执行。而情况2中,没有换行符,所以数据留在用户缓冲区中,没有刷新到内核缓冲区,等调用fork的时候,创建子进程,子进程又继承了父进程的代码和数据,故此就有了两份数据“hello world!”当父子进程退出时,都会刷新用户缓冲区,于是内核缓冲区中就有两份hello world。
二.磁盘文件
2.1 磁盘
磁盘是计算机主要的存储介质,可以存储大量的二进制数据,并且断电后也能保持数据不丢失。早期计算机使用的磁盘是软磁盘(Floppy Disk,简称软盘),如今常用的磁盘是硬磁盘([Hard disk](https://baike.baidu.com/item/Hard disk/2806058?fromModule=lemma_inlink),简称硬盘)。现在的pc大部分都用的是SSD固态硬盘(电)。
2.2 磁盘的物理结构
- 磁盘中有许多盘片,每一个盘片都有两个盘面,盘面上有若干磁道,磁道由若干扇区组成,磁盘的基本存储单元是扇区(512字节),多个盘片同半径的所有磁道构成一个柱面
2.3 硬件寻址方法-CHS
确定一个扇区的方式:先定位在哪个盘面上(磁头head),然后在定义哪个柱面cylinder(磁道),最后根据扇区(sector)编号即可定位某一个扇区。这种寻址方法也叫做CHS定位法。
2.4 操作系统寻址方式-LBA
操作系统的寻址方式和硬件的寻址方式需要解耦合,所以操作系统需要有一套新的地址。os将盘面逻辑抽象成线性的(类似以前的那种磁带全部展开后)。
将这样的结构看作一个数组,每一个扇区占一个数组下标,这样就可以轻易的获取每个扇区的地址。但是操作系统一次IO的基本单位是块(4KB),所以将8个扇区看作一个块,然后重新抽象得到下图。下面这样的地址叫做LBA-逻辑块地址。磁盘也叫做块设备,以块为单位进行IO。
2.5 磁盘分区管理
我们电脑上只带有一块盘,但是为了更好的管理,所以将盘分为若干区,为了更好的管理一个区(区等同于c盘,d盘),又将区分为若干组。每个组内有许多字段。
Linux是将文件内容和属性分开存储的。
- Boot Block:存储了OS系统镜像以及开机启动的一些程序。
- Super Block(SB):存储了当前区的文件系统相关的属性,如文件系统名字,整个分区的情况,非常重要,损坏的话一个分区全部不能用,因此要在每个分组内做备份。Linux用的Ext系列的文件系统。
- Group Descriptor Table(GDT):存储了整个分组的情况
- Block Bitmap:位图结构,分别对应Data Blocks中的块是否可用
- Inode Bitmap:位图结构,对应Inode Table中的Inode是否有效
- Inode Table:存储文件属性。文件属性的集合叫做Inode节点,每一个Inode节点都有一个Inode编号(文件id)。
struct Inode{ int inode_num ; int block[NUM];///....};
- Data Blocks:存储文件内容,为了建立文件属性和内容的联系,故此每个Inode节点里面都有一个数组,指明哪个块是属于本文件,可用建立直接映射,二级映射,三级映射。
os查找文件:
ls -li
:查看当前目录下所有文件的inode编号
- 先找到文件对应的Inode编号
- 在Inode Table中找到Inode节点
- 根据Inode节点获得其内容块的地址、
2.6 Inode节点
struct inode
{int inode_number; //inode 编号int ref_count; // 硬链接数int modes; //权限size_t uid;size_t size;//....int databloacks[NUM]; //内容
};
- inode里面并没有文件名,因为操作系统并不需要文件名来标识文件,而是通过inode_编号来标识文件的。文件名只是给用户看的。
- 我们用
touch
命令的时候,是os先遍历访问InodeBitmap寻找空闲的Inode Table,创建Inode,然后在当前目录下用Inode编号和文件名建立一个映射关系。目录也是一个文件,目录里面存储的是文件名和Inode编号的映射关系 - 增删查改文件都是先根据文件名找到Inode编号
三.软、硬链接
3.1 软链接
ln -s myfile myfile-soft
- myfile-soft为myfile的链接文件,这个链接文件的内容为myfile的路径。
- 软链接的作用:便于执行程序,类似于Windows中的桌面快捷方式
3.2 硬链接
ln myfile myfile-hard
- 给myfile建立一个硬链接文件myfile-hard
功能:
Linux下,每一个目录下都有两个特殊目录.
和..
,一个点代表当前路径,两个点代表上级路径,为什么呢?因为一个点是当前路径的硬链接,两个点是上级路径的硬链接。这两个特殊路径使得路径切换更加容易。
- Linux下,不容许用户给目录建立硬链接,防止出现环路问题,而
.
和..
是操作系统可用识别的特殊路径。
3.3软硬链接的区别
- 通过观察创建的文件inode编号,可用知道硬链接并没有新建inode节点,而是和myfile指向同一个节点
- 软链接新建了一个文件,其有自己的inode节点和内容
- 硬链接数:类似于引用计数,当值为0的时候,就会释放inode节点。
相关文章:

Linux_文件系统
假定外部存储设备为磁盘,文件如果没有被使用,那么它静静躺在磁盘上,如果它被使用,则文件将被加载进内存中。故此,可以将文件分为内存文件和磁盘文件。 内存文件 磁盘文件 软、硬链接 一.内存文件 1.1 c语言的文件接口 …...

算法沉淀——链表(leetcode真题剖析)
算法沉淀——链表 01.两数相加02.两两交换链表中的节点03.重排链表04.合并 K 个升序链表05.K个一组翻转链表 链表常用技巧 1、画图->直观形象、便于理解 2、引入虚拟"头节点" 3、要学会定义辅助节点(比如双向链表的节点插入) 4、快慢双指针…...

Flink从入门到实践(一):Flink入门、Flink部署
文章目录 系列文章索引一、快速上手1、导包2、求词频demo(1)要读取的数据(2)demo1:批处理(离线处理)(3)demo2 - lambda优化:批处理(离线处理&…...

python分离字符串 2022年12月青少年电子学会等级考试 中小学生python编程等级考试二级真题答案解析
目录 python分离字符串 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python分离字符串 2022年12月 python编程等级考试级编程题 一、题目要…...

Excel练习:折线图突出最大最小值
Excel练习:折线图突出最大最小值 要点:NA值在折现图中不会被绘制,看似一条线,实际是三条线。换成0值和""都不行。 查看所有已分享Excel文件-阿里云 学习的这个视频:Excel折线图,…...

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之MenuItem组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之MenuItem组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、MenuItem组件 用来展示菜单Menu中具体的item菜单项。 子组件 无。 接口 Men…...
Mockito测试框架中的方法详解
这里写目录标题 第一章、模拟对象1.1)①mock()方法:1.2)②spy()方法: 第二章、模拟对象行为2.1)模拟方法调用①when()方法 2.2)模拟返回值②thenReturn(要返回的值)③doReturn() 2.3)模拟并替换…...

Atcoder ABC339 A - TLD
TLD 时间限制:2s 内存限制:1024MB 【原题地址】 所有图片源自Atcoder,题目译文源自脚本Atcoder Better! 点击此处跳转至原题 【问题描述】 【输入格式】 【输出格式】 【样例1】 【样例输入1】 atcoder.jp【样例输出1】 jp【样例说明…...
企业级DevOps实战
第1章 Zookeeper服务及MQ服务 Zookeeper(动物管理员)是一个开源的分布式协调服务,目前由Apache进行维护。 MQ概念 MQ(消息队列)是一种应用程序之间的通信方法,应用程序通过读写出入队列的消息࿰…...

C++中的new和delete
1.new和delete的语法 我们知道C语言的内存管理方式是malloc、calloc、realloc和free,而我们的C中除了可以使用这些方式之外还可以选择使用new和delete来进行内存管理。 new和delete的主要语法如下 从上面的代码我们只能知道new要比malloc好写一些,但是其…...
rtt设备io框架面向对象学习-dac设备
目录 1.dac设备基类2.dac设备基类的子类3.初始化/构造流程3.1设备驱动层3.2 设备驱动框架层3.3 设备io管理层 4.总结5.使用 1.dac设备基类 此层处于设备驱动框架层。也是抽象类。 在/ components / drivers / include / drivers 下的dac.h定义了如下dac设备基类 struct rt_da…...

腾讯云幻兽帕鲁服务器配置怎么选择合适?
腾讯云幻兽帕鲁服务器配置怎么选?根据玩家数量选择CPU内存配置,4到8人选择4核16G、10到20人玩家选择8核32G、2到4人选择4核8G、32人选择16核64G配置,腾讯云百科txybk.com来详细说下腾讯云幻兽帕鲁专用服务器CPU内存带宽配置选择方法ÿ…...
796. 子矩阵的和
Problem: 796. 子矩阵的和 文章目录 思路解题方法复杂度Code 思路 这是一个二维前缀和的问题。二维前缀和的主要思想是预处理出一个二维数组,使得每个位置(i, j)上的值表示原数组中从(0, 0)到(i, j)形成的子矩阵中所有元素的和。这样,对于任意的子矩阵(x…...
如何在 Python 中处理 Unicode
介绍 Unicode 是世界上大多数计算机的标准字符编码。它确保文本(包括字母、符号、表情符号,甚至控制字符)在不同设备、平台和数字文档中显示一致,无论使用的操作系统或软件是什么。它是互联网和计算机行业的重要组成部分…...
CSDN文章导出PDF整理状况一览
最近CSDN有了导出文章PDF功能,导出的PDF还可以查询, 因此,把文章导出PDF,备份一下自己的重要资料。 目前整理内容如下 No.文章标题整理时间整理之后 文章更新Size (M)10001_本地电脑-开发相关软件保持位…...
jmeter-05变量(用户定义变量,用户参数,csv文档参数化)
文章目录 一、jmeter有三种变量二、用户定义变量(这个更多的可以理解为全局变量)1、设置2、引用三、用户参数(可以理解为局部变量)1、设置2、引用3、用户参数化要配合线程组的线程数使用4、结果五、csv文档参数1、创建csv文件2、设置2、引用csv文件可以配合线程组的线程数,…...

CSS之水平垂直居中
如何实现一个div的水平垂直居中 <div class"content-wrapper"><div class"content">content</div></div>flex布局 .content-wrapper {width: 400px;height: 400px;background-color: lightskyblue;display: flex;justify-content:…...

2.8日学习打卡----初学RabbitMQ(三)
2.8日学习打卡 一.springboot整合RabbitMQ 之前我们使用原生JAVA操作RabbitMQ较为繁琐,接下来我们使用 SpringBoot整合RabbitMQ,简化代码编写 创建SpringBoot项目,引入RabbitMQ起步依赖 <!-- RabbitMQ起步依赖 --> <dependency&g…...

Unity学习笔记(零基础到就业)|Chapter02:C#基础
Unity学习笔记(零基础到就业)|Chapter02:C#基础 前言一、复杂数据(变量)类型part01:枚举数组1.特点2.枚举(1)基本概念(2)申明枚举变量(3ÿ…...
容器化的基础概念:不可变基础设施解释:将服务器视为乐高积木,而非橡皮泥。
不可变基础设施解释:将服务器视为乐高积木,而非橡皮泥。 想象一下用乐高积木代替橡皮泥进行搭建。使用橡皮泥时,您可以直接塑形和改变它。而使用乐高积木,您需要逐个零件搭建特定结构,并在需要时整体替换它们。这就是…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...

二叉树-144.二叉树的前序遍历-力扣(LeetCode)
一、题目解析 对于递归方法的前序遍历十分简单,但对于一位合格的程序猿而言,需要掌握将递归转化为非递归的能力,毕竟递归调用的时候会调用大量的栈帧,存在栈溢出风险。 二、算法原理 递归调用本质是系统建立栈帧,而非…...