文件系统与inode编号

文件描述符fd

0&1&2

Linux 进程默认情况会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2. 0,1,2对应的物理设备一般是:键盘,显示器,显示器 所以输入输出还可以采用如下方式

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>int main()
{char buf[1024];ssize_t s = read(0, buf, sizeof(buf));if (s > 0){buf[s] = 0;write(1, buf, strlen(buf));write(2, buf, strlen(buf));}return 0;
}

文件描述符就是从 0 开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file 结构体。表示一个已经打开的文件对象。而进程执行 open 系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表 files_struct, 该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件

文件描述符的分配规则

我们通过一段代码来比较直接的观察
演示代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{int fd = open("myfile", O_RDONLY);if (fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);close(fd);return 0;
}

运行结果:

因为0,1,2文件描述符都已经被占用了,直接从3开始好像挺好理解的。我们猜测文件描述符是从没有被占用的数字从小到大分配的,所以是不是呢?我们通过下面这段代码来验证一下
演示代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{int fd1 = open("log1.txt", O_WRONLY | O_CREAT);int fd2 = open("log2.txt", O_WRONLY | O_CREAT);int fd3 = open("log3.txt", O_WRONLY | O_CREAT);if (fd1 < 0 || fd2 < 0 || fd3 < 0){perror("open");return 1;}printf("fd1: %d\n", fd1);printf("fd2: %d\n", fd2);printf("fd3: %d\n", fd3);close(fd1);close(fd2);close(fd3);return 0;
}
运行结果
那如果我们先关掉 0,2呢(1是标准输出,为了方便观察结果,就不关闭它啦)
来看下代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{close(0);close(2);int fd1 = open("log1.txt", O_WRONLY | O_CREAT);int fd2 = open("log2.txt", O_WRONLY | O_CREAT);int fd3 = open("log3.txt", O_WRONLY | O_CREAT);if (fd1 < 0 || fd2 < 0 || fd3 < 0){perror("open");return 1;}printf("fd1: %d\n", fd1);printf("fd2: %d\n", fd2);printf("fd3: %d\n", fd3);close(fd1);close(fd2);close(fd3);return 0;
}

运行结果

结论:文件描述符是按照未分配的数字从小到大分配的。

重定向

那如果关闭1呢?
演示代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{close(1);int fd = open("myfile", O_WRONLY | O_CREAT, 0644);if (fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);printf("hello dear programmer");fflush(stdout);//刷新缓冲区⭐close(fd);exit(0);
}

运行结果:
显示器上什么页没有输出,但当我们打开文件myfile发现,原本要输入到显示器的内容全部输入到文件中了,这就叫重定向。
通过这张图片,我们来了解一下重定向的本质

dup2系统调用

man dup2 
使用示例:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{int fd = open("./log", O_CREAT | O_RDWR);if (fd < 0){perror("open");return 1;}close(1);dup2(fd, 1);for (;;){char buf[1024] = {0};ssize_t read_size = read(0, buf, sizeof(buf) - 1);if (read_size < 0){perror("read");break;}printf("%s", buf);fflush(stdout);}return 0;
}

运行结果:

FILE
因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访问的。 所以C库当中的FILE必定封装了fd。
#include <stdio.h>
#include <string.h>
int main()
{const char *msg0 = "hello printf\n";const char *msg1 = "hello fwrite\n";const char *msg2 = "hello write\n";printf("%s", msg0);fwrite(msg1, strlen(msg0), 1, stdout);write(1, msg2, strlen(msg2));fork();return 0;
}

运行结果:

但如果对进程实现输出重定向呢?执行 ./test > file 后,结果变成了

我们发现 printf fwrite (库函数)都输出了 2 次,而 write 只输出了一次(系统调用)。为什么呢?这里我们猜测可能和fork有关,通过屏蔽fork,我们发现结果是
(1)一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。
(2)printf fwrite 库函数会自带缓冲区(进度条例子就可以说明),当发生重定向到普通文件时,数据 的缓冲方式由行缓冲变成了全缓冲。
(3)我们放在缓冲区中的数据,就不会被立即刷新,甚至fork之后
(4)但是进程退出之后,会统一刷新,写入文件当中。
(5)但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的 一份数据,随即产生两份数据。
(6)write 没有变化,说明没有所谓的行缓冲
综上: printf fwrite 库函数会自带缓冲区,而 write 系统调用没有带缓冲区。另外,我们这里所说的缓冲区,都是用户级缓冲区。其实为了提升整机性能,OS也会提供相关内核级缓冲区,不过不在我们讨论范围之内。那这个缓冲区谁提供呢? printf fwrite 是库函数, write 是系统调用,库函数在系统调用的“上层”, 是对系统调用的“封装”,但是 write 没有缓冲区,而 printf fwrite 有,足以说明,该缓冲区是二次加上的,又因为是C,所以由C标准库提供
//缓冲区相关
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr;   /* Current read pointer */
char* _IO_read_end;   /* End of get area. */
char* _IO_read_base;  /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr;  /* Current put pointer. */
char* _IO_write_end;  /* End of put area. */
char* _IO_buf_base;   /* Start of reserve area. */
char* _IO_buf_end;    /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base;  /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */

理解文件系统

我们使用  ls -l    的时候看到的除了看到文件名,还看到了文件元数据。
 
 
每行包含 7 列:
         模式,硬链接数,文件所有者 ,组,大小文件名,最后修改时间
 
ls -l 读取存储在磁盘上的文件信息,然后显示出来
另外 stat命令也可以查看文件信息

文件系统

Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如 mke2fs -b 选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的
Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子
超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了
GDT,Group Descriptor Table:块组描述符,描述块组属性信息
块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用
inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
i节点表:存放文件属性如文件大小,所有者,最近修改时间等
数据区:存放文件内容
将属性和数据分开存放的想法看起来很简单,但实际上是如何工作的呢?我们通过touch一个新文件来看看如何工作。
[hty@iZ2vcboxg2e41nj4s5s6zrZ test]$ cd day3
[hty@iZ2vcboxg2e41nj4s5s6zrZ day3]$ touch file
[hty@iZ2vcboxg2e41nj4s5s6zrZ day3]$ ls -i file
1581596 file

创建一个新文件主要有一下4个操作:
1. 存储属性
内核先找到一个空闲的i节点(这里是263466)。内核把文件信息记录到其中。
2. 存储数据
该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第一块数据
复制到300,下一块复制到500,以此类推。
3. 记录分配情况
文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。
4. 添加文件名到目录
新的文件名abc。linux如何在当前的目录中记录这个文件,内核将入口(263466,file)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。
下面解释一下文件的三个时间:
         Access 最后访问时间
        Modify 文件内容最后修改时间
        Change 属性最后修改时间

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中国非晶纳米晶行业市场预测与投资战略报告(2023版)

内容简介&#xff1a; 由于性能优异&#xff0c;非晶材料从20世纪80年代开始成为中国外科学界研究重点&#xff0c;目前美、日、德已经具备完善的生产规模&#xff0c;大量的非晶合金产品逐渐取代硅钢、铁氧体等。 2021年之前&#xff0c;中国铁基非晶带材企业有12家&#xf…

AVR128单片机 自动售水机

一、系统方案 1、设计使用两个按键分别为S1和S2及一个发光二极管LED。S1为出水控制按键&#xff0c;当S1按下&#xff0c;表示售水机持续出水&#xff0c;继电器&#xff08;库元件relay&#xff09;接通&#xff0c;指示灯LED亮。S2为停水控制键&#xff0c;当S2按下&#xff…

CSS面试题

CSS面试题 1.说说flexbox&#xff08;弹性盒布局模型&#xff09;,以及适用场景&#xff1f;flex-directionflex-wrapflex-flowjustify-contentalign-itemsalign-content 2.让Chrome支持小于12px 的文字方式有哪些&#xff1f;区别&#xff1f;3.css选择器有哪些? 优先级? 哪…

OSCS 安全周报第 58 期:VMware Aria Operations SSH 身份验证绕过漏洞 (CVE-2023-34039)

​ 本周安全态势综述 OSCS 社区共收录安全漏洞 3 个&#xff0c;公开漏洞值得关注的是 VMware Aria Operations SSH 身份验证绕过漏洞( CVE-2023-34039 )、Apache Airflow Spark Provider 反序列化漏洞( CVE-2023-40195 )。 针对 NPM 仓库&#xff0c;共监测到 324 个不同版本…

9月3日,每日信息差

第一、中国中铁与广州市城中村改造做地主体签署战略合作框架协议。根据协议&#xff0c;双方将积极响应广州市统筹做地推进高质量发展工作精神&#xff0c;充分发挥双方优势资源&#xff0c;共同加大在物业复建安置、基础设施建设、综合开发投资、城中村改造&#xff08;微改造…

volatile 关键字 与 CPU cache line 的效率问题

分析&回答 Cache Line可以简单的理解为CPU Cache中的最小缓存单位。目前主流的CPU Cache的Cache Line大小都是64Bytes。假设我们有一个512字节的一级缓存&#xff0c;那么按照64B的缓存单位大小来算&#xff0c;这个一级缓存所能存放的缓存个数就是512/64 8个。具体参见下…

【跟小嘉学 Rust 编程】二十三、Cargo 使用指南

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…

百度低质量站点怎么办?解决百度低质量站点的方法和工具

百度低质量站点怎么恢复&#xff1f;这是许多网站主和运营人员在SEO优化过程中经常面临的一个问题。百度作为中国最大的搜索引擎&#xff0c;对于网站收录和排名具有至关重要的影响。然而&#xff0c;由于各种原因&#xff0c;有些网站可能面临被百度降权或收录减少的情况。那么…

go、Java、python三门语言的优缺点和各自擅长做什么

Go、Java和Python都是目前非常流行和实用的编程语言&#xff0c;它们各有各的特点和适用场景&#xff0c;没有绝对的优劣之分&#xff0c;只有适合不适合的问题。下面我就简单地对比一下它们的主要特征和应用领域。 Go语言是一种简洁、高效、并发的编程语言&#xff0c;它可以…

vue3.3 ~

defineModel 原本&#xff1a; // 1 defineProps({modelValue: {type: Number,required: true,default: 0} })defineProps([modelValue]) // 2 const emit defineEmits([update:modelValue])现在&#xff1a; const value defineModel<number>({ default: 0 })defin…

Medium: Where to Define Qualified users in A/B testing?

1. Common AB Testing Setup Issue (Framework) 局限性: unqualified users will also be considered and mess up experimentation results.

SeaTunnel扩展Transform插件,自定义转换插件

代码结构 在seatunnel-transforms-v2中新建数据包名&#xff0c;新建XXXTransform&#xff0c;XXXTransformConfig&#xff0c;XXXTransformFactory三个类 自定义转换插件功能说明 这是个适配KafkaSource的转换插件&#xff0c;接收到的原文格式为&#xff1a; {"path&…

华为OD机试 - 找出经过特定点的路径长度 - 深度优先搜索(Java 2022 Q4 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#…

【记录】USSOCOM Urban3D 数据集读取与处理

Urban3D数据集内容简介 Urban3D数据集图像为正摄RGB影像&#xff0c;分辨率为50cm。 从SpaceNet上使用aws下载数据&#xff0c;文件夹结构为&#xff1a; |- 01-Provisional_Train|- GT|- GT中包含GTC&#xff0c;GTI&#xff0c;GTL.tif文件&#xff0c;GTL为ground truth b…

合并两个有序链表(每日一题)

“路虽远&#xff0c;行则将至” ❤️主页&#xff1a;小赛毛 ☕今日份刷题&#xff1a;合并两个有序链表 题目描述&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例1&#xff1a; 输入&#xff1a;l1 …

web pdf 拖拽签章

web pdf 拖拽签章 主要通过火狐的pdfjs 来实现 1. 下载js 并编译 地址 https://mozilla.github.io/pdf.js/ 按照官网当下下载并编译就得到了js 2.其实也没有什么好讲的&#xff0c;都是用的js中的方法&#xff0c;官网中都有 按照步骤就能生成一个document元素&#xff0c;然…

Linux系统gdb调试常用命令

GDB&#xff08;GNU调试器&#xff09;是一款常用的调试工具&#xff0c;用于调试C、C等编程语言的程序。以下是一些常用的GDB命令&#xff1a; 1. 启动程序&#xff1a; - gdb <executable>&#xff1a;启动GDB调试器&#xff0c;并加载可执行文件。 2. 设置断点&a…

【真题解析】系统集成项目管理工程师 2023 年上半年真题卷(案例分析)

本文为系统集成项目管理工程师考试(软考) 2023 年上半年真题(全国卷),包含答案与详细解析。考试共分为两科,成绩均 ≥45 即可通过考试: 综合知识(选择题 75 道,75分)案例分析(问答题 4 道,75分)案例分析(问答题*4)试题一试题二试题三试题四案例分析(问答题*4) …

FANUC机器人电气控制柜内部硬件电路和模块详细介绍

FANUC机器人电气控制柜内部硬件电路和模块详细介绍 PSU电源单元 通过背板传输了如下电源 +5 +2.0V +3.3 +24v +24E +15V -15V 主板--接口描述: 主板内部结构: 面板电路板: 引申一下 KM21 与 KM22 的作用它们分别接至操作面板上上的急停按

基于RabbitMQ的模拟消息队列之五——虚拟主机设计

文章目录 一、创建VirtualHost类二、初始化三、API1.创建交换机2.删除交换机3.创建队列4.删除队列5.创建绑定6.删除绑定7.发送消息转发规则 8.订阅消息1.消费者管理2.推送消息给消费者 3.添加一个消费者管理ConsumerManager9.确认消息 创建VirtualHost类。 1.串起内存和硬盘的数…