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

【Linux】深入理解Linux文件系统:从C接口到内核设计哲学


文章目录

  • 前言
  • 一、C语言中的文件接口
    • 1. 文件指针(句柄)FILE*
      • 以写方式打开文件,若文件不存在会新建一个文件
      • W写入方式,在==打开文件之前==都会将文件内容全部清空
      • 追加写方式,其用法与写方法一致,不同在于a方法可以在文件结尾写入
  • 二、认识文件系统调用
    • Linux下的系统调用open()
      • 第一个参数为文件路径
      • 第二个参数为操作文件的方式
      • 第三个可选参数是更改创建文件的默认权限:
  • 三、访问文件的本质
  • 四、重定向与缓冲区
    • 自定义重定向系统调用接口dup2
  • 再谈“一切皆文件”
    • 1. 外设设备与文件系统的关系
    • 2. 扩展思想:
  • 总结


前言

在计算机系统中,文件由内容数据和元数据属性共同构成。文件的完整生命周期分为两个阶段:

文件状态存储位置管理方式
未打开文件磁盘存储介质文件系统通过inode管理
已打开文件内存内核通过file结构体管理
  • 所有文件操作本质上都是进程与文件系统的交互
  • 打开文件需要将文件属性加载到内存
  • 文件内容采用按需加载策略(延迟加载)

研究文件系统本质是研究进程和文件之间的关系(文件是由进程打开的);未打开的文件存在磁盘上(存储介质),文件要被打开(属性)必须先要加载到内存;


一、C语言中的文件接口

基本输入输出 stdio.h
访问磁盘的过程称之为IO的过程,

1. 文件指针(句柄)FILE*

//C标准库通过FILE结构体封装文件描述符FILE *fopen(const char *path, const char *mode)
// mode参数决定了你的访问权限
mode说明特性
“w”写模式(清空文件)文件不存在时创建
“a”追加模式保留原内容,末尾写入
“r”读写模式文件必须存在

以写方式打开文件,若文件不存在会新建一个文件

若没有指定路径,程序会在默认当前路径下创建,当前路径指的是进程的当前路径(使用ls /proc/[pid] 查看到当前进程的cwd)。
在这里插入图片描述
同样的,修改当前进程的工作目录就可以改变创建文件的默认路径。

chdir("home/ys") //修改进程工作路径为home/ys

W写入方式,在打开文件之前都会将文件内容全部清空

在这里插入图片描述

上一个程序疑问:strlen要不要+1?

我们知道写入字符串时需要将\0也写入,我们试验之后发现文本中多了@^这样的乱码,推测这就是\0,只不过vim文本编辑器将其解释成了乱码符号。结论是strlen不需要+1,文件系统没有规定字符串必须以\0结尾

追加写方式,其用法与写方法一致,不同在于a方法可以在文件结尾写入

二、认识文件系统调用

c语言程序在启动时,会默认打开三个标准输入输出流文件:

stdin:键盘设备
stdout:显示器文件
stderr:显示器文件

文件其实是在磁盘上的,由于磁盘是外部设备,访问文件实际上是访问磁盘这样的硬件。不同的语言有不同的文件操作方式,但在底层用的是都是一样的实现方式——都需要调用系统接口open、read、write。

库函数(fopen,printf,fscanf等)访问硬件设备一定会通过系统调用来访问。

Linux下的系统调用open()

在这里插入图片描述

第一个参数为文件路径

  • 若pathname以路径的方式给出,则当需要创建该文件时,就在pathname路径下进行创建。
  • 若pathname以文件名的方式给出,则当需要创建该文件时,默认在当前路径下进行创建。(注意当前路径的含义)

第二个参数为操作文件的方式

方式含义
O_RDONLY以只读的方式打开文件
O_WRNOLY以只写的方式打开文件
O_APPEND以追加的方式打开文件
O_RDWR以读写的方式打开文件
O_CREAT当目标文件不存在时,创建文件

1. O_WRONLY是写方式,但是它并不会新建文件
2. O_CREAT打开文件时清空文件

3. O_APPEND 追加写选项
写入:

const char* message = "hello";
write(fd,message,strlen(message));
//write并不会对文件进行清空式写入。
int fd = open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666); //追加
write(fd,message,strlen(message),);

第三个可选参数是更改创建文件的默认权限:

//eg:
int fd = open("log.txt",O_WRONLY|O_CREAT); 

创建权限错误,所以新建文件时需要告诉接口权限是什么。
在这里插入图片描述

int fd = open("log.txt",O_WRONLY|O_CREAT,0666); 

在这里插入图片描述
这里创建出来的并不是666而是664,应该要想到之前学到的权限掩码(0002)的知识!

比特位级别的传参方式原理:
使用位图的方式,一次向操作系统传递多个标志位

三、访问文件的本质

可以将其类比系统管理进程(struct_task),Linux系统中一切皆文件,因此管理进程势必要通过先描述再组织的方法进行。要描述一个被打开的文件(struct_file),往往需要包含文件路径、文件基本属性(权限、大小、读写位置、访问用户的信息等)、文件的内核缓冲区信息、下一个struct_file的指针

一个进程可能会打开多个文件,那么进程与文件之间又是如何关联的?(1:n)

进程PCB中会存在一个结构体指针struct files_struct *files指向了一个结构体,该结构体存放了一个存放各种文件PCB指针的数组;因为是数组,所以这也解释了为什么open接口返回的是int类型的值了,进程根据这个下标就可以访问对应文件。

如果尝试打印一下返回值,发现文件描述符默认是从3开始的,那么0,1,2是什么文件呢?那就是标准输入输出错误流了!(stdin \ stdout \stderr

int fd = open("demo.txt",O_WRONLY |O_CREAT,0666);
cout << fd << endl; //3cout << stdin->_fileno << endl;//0
cout << stdout->_fileno << endl;//1
cout << stderr->_fileno << endl;//2

在这里插入图片描述
既然一切皆文件,那么输出流也是文件,因此我们可以使用以下代码向标准输出流文件中写入message信息:

const char* message = "hello";
write(1,message,strlen(message));// 1 就是标准输出流stdout

从标准输入流文件中读取buffer大小的字符放在buffer[1024]数组中 :

char buffer[1024];
read(0,buffer,sizeof(buffer));
printf("echo: %s\n",buffer);

四、重定向与缓冲区

文件描述符对应的分配规则是什么?

从0下标开始,寻找没有被使用的数组位置,它的下标就是新文件的文件描述符值。

假设我们有一个空文件log.txt,有如下代码,含义是将msg中的strlen长度的数据输出到显示器。

const char* msg = "hello linux\n";
write(1,msg,strlen(msg));

但如果先关闭了1描述符(即关闭标准输出流),除了显示器无法显示外

close(1);
int fd = open("log.txt", O_RDONLY | O_CREAT, 0666);//1
const char* msg = "hello linux\n";
write(1,msg,strlen(msg));//此时写入的就是1号文件描述符,即log.txt 文件

log.txt中居然存有数据。
这一工作,称为输出重定向。根据上面的知识可以意识到关闭了1描述符后,那么这里就是空着的,当使用open接口新建log.txt时,根据文件描述符分配规则,自然1号位就成为了log.txt的fd描述符,所以将本来要写入stdout的数据写入到了log.txt中。

自定义重定向系统调用接口dup2

int dup2(int oldfd,int newfd)
把oldfd复制到newfd
//oldfd 相当于 原本的 3 描述符
//newfd 相当于 原本的 1 描述符int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);
dup2(fd, 1); 

这里要注意的是,重定向中的拷贝,不是将文件描述符表中的下标进行拷贝,而是对下标处的内容(文件结构体指针)进行拷贝!

使用dup2在打开文件log.txt后,进行了输出重定向,将原本输出到显示器的内容写入到了log.txt文件中。再次更改代码open的宏参数(O_TRUNC -> O_APPEND),就成为了追加重定向操作。结果如下所示:
在这里插入图片描述
同样的,可以修改代码让其重定向标准输入流至文件(默认read从stdin文件读数据,重定向后,从log.txt文件中读)。这一过程称为输入重定向

在这里插入图片描述

以上是使用dup2重定向系统调用函数write、read,前面提到c语言printf、fprintf底层也是这样的文件描述符表的结构,那是否可以控制c语言中的输入输出呢?

dup2(fd,1);
printf("hello printf\n");
fprintf(stdout,"hello printf\n");

回想之前的章节介绍到echo指令,可以进行输出重定向,cat指令可以进行输入重定向

echo "hello" > log.txt   //输出重定向
cat < log.txt            //输入重定向
echo "hello" >> log.txt  //追加重定向

进程的替换不会影响文件的访问(包括重定向操作)——复习进程替换

stdout与stderr都是可以向显示器打印,为什么要有2?他们俩的区别是什么?

有如下代码,表示将字符串分别输出到1(标准输出流)和2(标准错误流)中。
在这里插入图片描述

$ ./mytest 1>normal.log 2>err.log
//将stdout的数据重定向至normal.log
//将stderr的数据重定向至err.log

在这里插入图片描述

实际上,1和2是相同的实现方式,只不过在使用中,相较于正常结果而言,更关注的是它的错误信息,而正常运行的信息往往很多,不便错误的筛查与纠正。因此,为了将错误信息分离出来,才有了标准错误流。

一个衍生用法:

$ ./mytest >normal.log 2>&1

再谈“一切皆文件”

1. 外设设备与文件系统的关系

在这之前我们知道:所有操作计算机的动作都是由进程执行的,包括文件的访问,每一种外设都要有描述他们的结构体对象(struct_dev)

此外,每一种外设都有其相独特的读写方法,纵然每个外设对应的访问实现方式不同(各家外设设备驱动的不同),而对于操作系统来看,这些外设无非都是一些需要进行读写的文件,而能够直接进行文件访问读写的就是进程(open接口),打开新的文件就会创建一个新的struct_file,这个结构体是不是很熟悉?在这个结构体中,就存在着能够指向该文件具体实现自身读写行为的指针(struct fils_operations*),例如(指向了不同磁盘的读写方法,不同键盘的读写方法)。

  • 在Linux中,将struct_file这一层的逻辑关系称为虚拟文件系统(VFS)

外设差异化被封装在驱动中:不同厂商的驱动实现自己的读写逻辑(如razer_keyboard_readlogitech_keyboard_read),但必须遵循操作系统定义的接口。
操作系统通过抽象层统一接口:上层应用只需调用 read()、write() 等标准接口,无需关心底层是罗技还是雷蛇设备。

2. 扩展思想:

这种设计模式与 面向对象编程中的多态性高度相似

​基类(抽象接口) ​:操作系统定义的设备驱动接口(如file_operations)。
​派生类(具体实现) ​:厂商驱动的读写函数(如雷蛇、罗技的实现)。
运行时多态 :通过函数指针动态绑定到具体实现。

通过这种机制,操作系统实现了外设的 ​​“高内聚、低耦合”​,使得硬件厂商可以自由创新,同时保持软件生态的兼容性。


总结

👍 ​感谢各位大佬观看。如果本文有帮助,请点赞收藏支持~

相关文章:

【Linux】深入理解Linux文件系统:从C接口到内核设计哲学

文章目录 前言一、C语言中的文件接口1. 文件指针&#xff08;句柄&#xff09;FILE*以写方式打开文件&#xff0c;若文件不存在会新建一个文件W写入方式&#xff0c;在打开文件之前都会将文件内容全部清空追加写方式&#xff0c;其用法与写方法一致&#xff0c;不同在于a方法可…...

基于尚硅谷FreeRTOS视频笔记——15—系统配制文件说明与数据规范

目录 配置函数 INCLUDE函数 config函数 数据类型 命名规范 函数与宏 配置函数 官网上可以查找 最核心的就是 config和INCLUDE INCLUDE函数 这些就是裁剪的函数 它们使用一个ifndef。如果定义了&#xff0c;就如果定义了这个宏定义&#xff0c;那么代码就生效。 通过ifn…...

Linux网络编程 深入解析TFTP协议:基于UDP的文件传输实战

知识点1【TFTP的概述】 学习通信的基本&#xff1a;通信协议&#xff08;具体发送上面样的报文&#xff09;、通信流程&#xff08;按照什么步骤发送&#xff09; 1、TFTP的概述 tftp&#xff1a;简单文件传输协议&#xff0c;**基于UDP&#xff0c;**不进行用户有效性验证 …...

c# MES生产进度看板,报警看板 热流道行业可用实时看生产进度

MES生产进度看板&#xff0c;报警看板 热流道行业可用实时看生产进度 背景 本软件是给宁波热流道行业客户开发的生产电子看板软件系统 功能 1.录入工艺流程图&#xff08;途程图&#xff09;由多个站别组成。可以手动设置每个工艺站点完成百分比。 2.可以看生成到哪个工…...

Qt unknown module(s) in qt:serialport解决方法

在Ubuntu和CentOS系统中,若使用Qt时遇到Unknown module(s) in QT: serialport错误,通常是由于未正确安装Qt的串口模块(QSerialPort)或项目配置不当导致。以下是针对两种系统的解决方案: 一、安装Qt串口模块 1. Ubuntu/Debian系列 安装开发包: 执行以下命令安装Qt5串口模…...

AtCoder ABC402 A~D 题解

A - CBC 题目大意 给点字符串 S S S&#xff0c;输出其中所有大写字母。 思路 根据题意模拟即可。 代码 #include <cstdio> #include <iostream> #include <algorithm> using namespace std;int main() {string s;cin >> s;for (int i 0; i &l…...

2025.04.19-阿里淘天春招算法岗笔试-第二题

📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 02. 秒杀顺子查找 问题描述 K小姐是一名热爱扑克牌的玩家。她定义一个数列是"顺子",当且仅当将该数列排序后,每个元素恰好比前一个元素大 1 1...

初识Redis · C++客户端string

目录 前言&#xff1a; string的API使用 set get&#xff1a; expire: NX XX: mset,mget&#xff1a; getrange setrange: incr decr 前言&#xff1a; 在前文&#xff0c;我们已经学习了Redis的定制化客户端怎么来的&#xff0c;以及如何配置好Redis定制化客户端&…...

华硕原厂系统枪神9/9p超竟版-WIN11原装开箱出厂系统安装

华硕原厂系统枪神9/9p超竟版-WIN11-24H2-专业工作站版本安装可带F12-ASUSRecovery恢复功能 适用机型&#xff1a; G635LX、G635LW、G835LX、G835LW、G615LW、G615LP、G615LM、G615LH G815LW、G815LP、G815LM、G815LH、G635LR、G835LR、G615LR、G815LR 远程恢复安装&#xff…...

CF1016赛后总结

文章目录 前言T1:Ideal GeneratorT2&#xff1a;Expensive NumberT3:Simple RepetitionT4&#xff1a;Skibidi TableT5:Min Max MEXT6:Hackers and Neural NetworksT7:Shorten the Array 前言 由于最近在半期考试&#xff0c;更新稍微晚了一点&#xff0c;还望大家见谅 &#…...

QT聊天项目DAY06

1.从git上同步项目 编译测试&#xff0c;编译通过 Post请求测试 测试成功 2. email is 打印有问题&#xff0c;检查 解析结果是存储在jsonResult中的&#xff0c;修改 3. 客户端实现Post验证码请求 3.1 同步Qt客户端项目 检查QT版本&#xff0c;由于我在公司用的还是QT5.12.9…...

GNU,GDB,GCC,G++是什么?与其他编译器又有什么关系?

文章目录 前言1. GNU和他的工具1.1 gcc与g1.2 gdb 2.Windows的Mingw/MSVC3.LLVM的clang/clang4.Make/CMake 前言 在开始之前我们先放一段Hello World&#xff1a;hello.c #include <stdio.h>int main() {printf("Hello World");return 0; }然后就是一段老生常…...

【AI提示词】IT专家顾问

提示说明 IT 专家顾问是一位专注于IT行业的专家&#xff0c;拥有深厚的技术背景和广泛的知识储备。他们能够为企业、政府机构或其他组织提供技术支持、解决方案设计和战略规划。 提示词 # Role: IT 专家顾问## Profile - **语言**: 中文 - **描述**: IT 专家顾问是一位专注于…...

笔记整理五

STP生成树 stp生成树是用于解决二层环路问题的协议。 二层环路为有以下三种&#xff1a; 1.广播风暴 2.MAC地址的偏移&#xff08;每一次循环&#xff0c;都会导致交换机来回刷新MAC地址表记录&#xff09; 3.多帧复制 stp生成树&#xff1a;需要将原本的环型拓扑结构转换…...

Java中“this”关键字梳理详解

在Java中&#xff0c;this 是一个非常重要的关键字&#xff0c;它表示当前对象的引用。也就是说&#xff0c;当你在某个类的实例方法或构造器中时&#xff0c;this 指向调用该方法或创建的当前对象实例。以下将结合代码示例和具体场景&#xff0c;详细讲解 this 的用法及其作用…...

mybatis plus打印sql日志到指定目录

1、mybatis plus打印sql日志 参考文档&#xff1a;mybatis plus打印sql日志_mybatisplus日志打印-CSDN博客 2、修改 修改InfoLevelLogger Override public void debug(String s) {// 修改这里logger.info(s);log.debug(s); } 增加&#xff1a;log.debug(s); 修改logback.x…...

奥比中光tof相机开发学习笔记

针对奥比中光 tof相机&#xff0c;官方提供的资料如下ProcessOn Mindmap|思维导图 Orbbec SDK Python Wrapper基于Orbbec SDK进行设计封装&#xff0c;主要实现数据流接收&#xff0c;设备指令控制。下面就其开发适配进行如下总结&#xff1a; &#xff08;1&#xff09;系统配…...

Oracle游标和触发器

--1.游标 --什么是游标 --游标是数据库在内存中开辟的数据缓冲区 --作用&#xff1a;用于遍历查询返回之后的结果集&#xff08;多条数据结果&#xff09; --游标分类&#xff1a;隐式游标&#xff0c;显示游标&#xff0c;REF游标&#xff08;动态游标&#xff09; --游标的状…...

【面试向】点积与注意力机制,逐步编码理解自注意力机制

点积&#xff08;dot product&#xff09;两个向量点积的数学公式点积&#xff08;dot product&#xff09;与 Attention 注意力机制&#xff08;Attention&#xff09;注意力机制的核心思想注意力机制中的缩放点积自注意力机制中&#xff0c;谁注意谁&#xff1f; 逐步编码理解…...

00.IDEA 插件推荐清单(2025)

IDEA 插件推荐清单 精选高效开发必备插件&#xff0c;提升 Java 开发体验与效率。 参考来源&#xff1a;十六款好用的 IDEA 插件&#xff0c;强烈推荐&#xff01;&#xff01;&#xff01;不容错过 代码开发助手类 插件名称功能简介推荐指数CodeGeeX智能代码补全、代码生成、…...

一个 CTO 的深度思考

今天和一些同事聊了一会&#xff0c;以下是我的观点 我的观点&#xff0c;成年人只能筛选&#xff0c;不能培养在组织中&#xff0c;应该永远向有结果的人看齐。不能当他站出来讲话的时候&#xff0c;大家还要讨论讨论&#xff0c;他虽然拿到结果了&#xff0c;但是他就是有一…...

MVC/MVVM 高级应用的深度解析

状态共享与同步 跨组件状态管理策略 状态变更的传播机制优化 状态快照与时间旅行调试 状态持久化 本地存储策略 状态序列化与反序列化 与服务端状态同步 数据绑定进阶 双向绑定优化 脏检查机制优化 基于Proxy/Object.defineProperty的实现差异 批量更新策略 自定义…...

SQL通用语法和注释,SQL语句分类(DDL,DML,DQL,DCL)及案例

目录 SQL通用语法和注释 SQL语句分类&#xff08;DDL&#xff0c;DML&#xff0c;DQL&#xff0c;DCL&#xff0c;TPL&#xff0c;CCL&#xff09; DDL&#xff08;数据定义语言&#xff09; 数据库操作 查询&#xff08;SHOW、SELECT&#xff09; 创建&#xff08;CREAT…...

当算力遇上马拉松:一场科技与肉身的极限碰撞

目录 一、从"肉身苦修"到"科技修仙" 二、马拉松的"新大陆战争" 三、肉身会被算法"优化"吗? 马拉松的下一站是"人机共生"时代 当AI能预测你的马拉松成绩,算法能规划最佳补给方案,智能装备让训练效率翻倍——你还会用传…...

AUTOSAR图解==>AUTOSAR_SWS_KeyManager

AUTOSAR KeyManager详细分析 AUTOSAR 4.4.0 版本密钥与证书管理模块技术分析 目录 1. 概述2. KeyManager架构 2.1 KeyManager在AUTOSAR架构中的位置2.2 架构说明 3. KeyManager模块结构 3.1 模块组件详解3.2 配置项说明 4. KeyManager证书验证流程 4.1 证书验证流程分析 5. Ke…...

用usb网卡 虚拟机无法开到全双工的解决办法

今天突发奇想 给unraid宿主机插了两个一摸一样的usb网卡 2.5g的 直通给不同的虚拟机 这里unraid需要安装"USB Manager" 请给unraid自备环境 直通的时候 第一次还没生效 看不到网卡 我又在unraid的管理界面 顶部可以看到多出来一个 "usb"页面 打开可…...

5. 话题通信 ---- 发布方和订阅方python文件编写

本节对应赵虚左ROS书籍的2.1.3 以10hz,发布消息和消息的订阅 1)在功能包下新建scripts文件夹&#xff0c;在scripts文件夹下新建python文件&#xff0c;写入 #! /usr/bin/env pythonfrom std_msgs.msg import String import rospyif __name__ "__main__":rospy.i…...

Jsp技术入门指南【七】JSP动作讲解

Jsp技术入门指南【七】JSP动作讲解 前言一、什么是JSP动作&#xff1f;二、核心JSP动作详解1. jsp:include&#xff1a;动态包含其他页面与<% include %>的区别 2. jsp:forward&#xff1a;请求转发到另一个页面3. jsp:param&#xff1a;为动作传递参数4. jsp:useBean&am…...

10软件测试需求分析案例-查询学习信息

用户登录系统后&#xff0c;进入查询学生信息界面&#xff0c;输入查询字段值&#xff0c;点击查询按钮后&#xff0c;展示查询到的学生信息&#xff0c;可以重新输入字段值进行查询。 查询学生信息属于学生信息管理的子菜单&#xff0c;可以根据学号、姓名、性别查询。老师登录…...

基于尚硅谷FreeRTOS视频笔记——6—滴答时钟—上下文切换

FreeRTOS滴答 FreeRTOS需要有一个时钟参照&#xff0c;并且这个时钟不会被轻易打断&#xff0c;所以最好选择systick 为什么需要时间参照 就是在高优先级任务进入阻塞态后&#xff0c;也可以理解为进入delay&#xff08;&#xff09;函数后&#xff0c;需要有一个时间参照&…...