【Linux】封装一下简单库 理解文件系统

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

一、封装一下简单库

二、理解一下stdin(0)、stdout(1)、stderr(3)

2.1、为什么要有0、1、2呢?

2.2、特点

2.3、如果我想让2也和1重定向到一个文件中?

三、理解文件系统

3.1、看看物理磁盘

3.2、了解一下磁盘的储存结构

3.3、对磁盘的存储进行逻辑抽象

3.4、找到一个文件的步骤:

3.5、逆向的路径解析 --- OS自己做的

总结



前言

世上有两种耀眼的光芒,一种是正在升起的太阳,一种是正在努力学习编程的你!一个爱学编程的人。各位看官,我衷心的希望这篇博客能对你们有所帮助,同时也希望各位看官能对我的文章给与点评,希望我们能够携手共同促进进步,在编程的道路上越走越远!


提示:以下是本篇文章正文内容,下面案例可供参考

一、封装一下简单库

Stdio.h
#pragma once
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#define LINE_SIZE 1024
#define FLUSH_NOW  1
#define FLUSH_LINE 2
#define FLUSH_FULL 4// 文件结构体类型
struct _myFILE
{unsigned int flags;int fileno;// 缓冲区char cache[LINE_SIZE];// 文件的缓冲区int cap;int pos; // 下次写入的位置
};typedef struct  _myFILE myFILE;myFILE* my_fopen(const char* path, const char* flag);
void my_fflush(myFILE* fp);
ssize_t my_fwrite(myFILE* fp, const char* data, int len);
void my_fclose(myFILE* fp);
Mystdio.c
#define _CRT_SECURE_NO_WARNINGS 1#include "mystdio.h"myFILE* my_fopen(const char* path, const char* flag)
{int flag1 = 0;// 打开文件的模式int iscreate = 0;// 是否要创建文件mode_t mode = 0666;// 文件的初始权限if (strcmp(flag, "r") == 0){flag1 = (O_RDONLY);}else if (strcmp(flag, "w") == 0){flag1 = (O_WRONLY | O_CREAT | O_TRUNC);iscreate = 1;}else if (strcmp(flag, "a") == 0){flag1 = (O_WRONLY | O_CREAT | O_APPEND);iscreate = 1;}else{}int fd = 0;// 根据是否要创建文件来使用不同的open()函数if (iscreate)fd = open(path, flag1, mode);elsefd = open(path, flag1);if (fd < 0) return NULL;myFILE* fp = (myFILE*)malloc(sizeof(myFILE));if (!fp) return NULL;fp->fileno = fd;fp->flags = FLUSH_LINE;// 行刷新fp->cap = LINE_SIZE;// 缓冲区的容量fp->pos = 0;// 当前写入文件的位置return fp;
}void my_fflush(myFILE* fp)
{write(fp->fileno, fp->cache, fp->pos);fp->pos = 0;
}// 写入数据:把用户将数据写入stdout文件当中(语言级的文件缓冲区内),将语言级的缓冲区内的内容拷贝到OS的内核级的缓冲区内
ssize_t my_fwrite(myFILE* fp, const char* data, int len)
{// 写入操作本质是拷贝, 如果条件允许,就刷新,否则不做刷新// 将数据拷贝到语言级的缓冲区memcpy(fp->cache + fp->pos, data, len); //肯定要考虑越界, 自动扩容fp->pos += len;if ((fp->flags & FLUSH_LINE) && fp->cache[fp->pos - 1] == '\n'){// 将语言级的缓冲区的数据拷贝到OS中对应的文件的内核级缓冲区my_fflush(fp);}return len;
}void my_fclose(myFILE* fp)
{my_fflush(fp);close(fp->fileno);free(fp);
}
Testfile.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "mystdio.h"
#include <string.h>
#include <stdio.h>
#include <unistd.h>#define FILE_NAME "log.txt"int main()
{myFILE* fp = my_fopen(FILE_NAME, "w");if (fp == NULL) return 1;const char* str = "hello bit";int cnt = 10;char buffer[128];while (cnt){sprintf(buffer, "%s - %d", str, cnt);my_fwrite(fp, buffer, strlen(buffer)); // strlen()+1不需要cnt--;sleep(1);my_fflush(fp);}my_fclose(fp);return 0;
}

结论:C语言为什么要在FILE中提供用户级缓冲区 ----- 为了减少底层调用系统调用的次数,让使用C语言的IO函数(printf,fprintf)效率更高。

二、理解一下stdin(0)、stdout(1)、stderr(3)

2.1、为什么要有0、1、2呢?

  • 0、1 -----> 用户要知道数据从哪里来,数据要到哪里去。
  • 2 -----> 把正确的信息和错误的信息区分开来。

2.2、特点

我们是要将原本打印在屏幕行的数据打印在 log.txt 里,为什么stderr还在屏幕上显示?

标准输出重定向的本质:更改文件描述符表中下标为1的内容(地址)。下标为1的内容原先是显示器文件的地址,现在更改为 log.txt 文件的地址。

下标为1和下标为2的空间的地址都是指向显示器文件的;下标为2的空间中的地址没有被改变,依然指向显示器文件的地址。所以,stderr仍然打印在屏幕上。

2.3、如果我想让2也和1重定向到一个文件中?

./a.out 1>ok.log 2>err.log

将下标为1的内容更改成 ok.log 文件的地址;将下标为2的内容更改成 err.log 文件的地址;将正确和错误的信息分离开来。

./a.out 1>all.log 2>&1

将下标为1的内容更改成 all.log 文件的地址;取下标为1的内容的地址更改下标为2的内容;从而使2和1重定向到一个文件中。

C语言中的 perror 本质是向2对应的文件打印,printf() 本质是向1对应的文件打印。

C++中的 cout 对应的是 printf;cerr 对应的是 perror。

三、理解文件系统

3.1、看看物理磁盘

3.2、了解一下磁盘的储存结构

3.3、对磁盘的存储进行逻辑抽象

假如:一个磁盘有800GB,我们把800GB分为4个区,每个区200GB,再将每个分区分组,我们只要管理好每一个分组,就能管理好一个分区,进而管理好磁盘。

格式化:在每一个分区内部分组,然后写入文件系统的管理数据。

文件在磁盘存储的本质:=文件的内容+文件的属性数据。

Linux文件系统特定:文件内容和文件属性分开存储。

  • Block Group:许多个数据块(4kb)组成,用来存放文件的内容。
  • 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:block 和 inode的总量, 未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了
  • GDT,Group Descriptor Table:块组描述符,描述整个分组里的使用情况,比如:一共有多少inode,一共有多少数据块呢?inode、数据块和Bitmap已经被占据了多少呢?那么下一个被分配的inode编号是几?由GDT来进行统一管理。
  • 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用(比特位的位置,表示块号。比特位的内容,表示该块是否被占用。)
  • inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
  • i节点表:存放文件属性,如:文件大小,所有者,最近修改时间等。
  • 超级块(Super Block):不是每个分组都有的。分配inode编号的范围。如果一个磁盘的某一分组的Super Block不小心被刮花了,那么可以通过其它分组的Super Block来恢复。

我们寻找文件的时候,都必须先得到inode的编号。inode编号是以分区为单位的!

但是你凭什么直接拿到inode的编号,我们一直使用的都是文件名啊!!!!

谈谈目录:

目录 = 文件属性 + 文件内容。    目录也是一个文件。

  1. 一个目录下不能建立同名文件;
  2. 查找文件的顺序,文件名 -----> inode的编号;
  3. 目录的r,本质是是否允许我们读取目录的内容;目录的内容是:文件名与inode的映射关系!!!
  4. 目录的w,新建文件,最后一定要向当前所处的目录内容中写入,文件名与inode的映射关系。

如何理解文件的增删查改呢?

  • 增:建立文件名与inode的映射关系。
  • 删:将该文件的inode编号在位图中对应的比特位置为0。

我们常说的将系统格式化,恢复出厂设置,其实就是将位图中的1全部置为0。

3.4、找到一个文件的步骤:

我们找到一个指定的文件 -----> 文件所在的目录 ------> 打开目录 -----> 根据文件名与inode的映射关系 -----> 找到目标文件inode。

但是有一个前提是:inode的编号是不能跨分区的,我们怎么才能知道我们的文件在哪一个分区内呢?

结论:比如:我用的云服务器一般只有一个盘(vda),一个盘对应了一个分区,在Linux中要访问一个分区其实要将这个分区进行挂载的,挂载也就是将一个磁盘分区和文件系统的一个目录进行关联,所以,未来进入分区,其实是进入一个指定的目录的。

分区 ----> 写入文件系统(格式化)(就是将在分组中写入管理的数据,但是此时这个分区还不能使用) ----> 挂载到指定目录下 ----> 进入该目录,自然就在该目录的分区下 ----> 在指定的分区中进行文件操作。

这也就是我们在Linux系统中,定位一个文件,在任何时候,都要有路径的原因!!!因为有路径,你就知道在哪个分区。

3.5、逆向的路径解析 --- OS自己做的

要打开当前目录,当前目录也是一个文件,你得找到当前目录的inode,那么你就得找到当前目录的上级目录;所以Linux在找到任何一个路径下的一个文件时,Linux系统一定要给我们逆向的递归式的路径解析;直到找到了根目录,就类似于找到了一个递归出口一般,然后再反向的逐次打开我们的文件。

逆向的路径解析,我们的Linux系统会一直做,那么必然会导致效率方面下降,所以Linux系统为了支持逆向路径解析,系统会把已经解析过的路径给我们进行缓存起来;那么将来要打开文件时,把要解析的路径,先在缓存里找,找不到,再解析。


总结

好了,本篇博客到这里就结束了,如果有更好的观点,请及时留言,我会认真观看并学习。
不积硅步,无以至千里;不积小流,无以成江海。

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

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

相关文章

uni-app 微信小程序设置全局转发给朋友、分享到朋友圈

小程序右上角原生菜单自带的分享按钮&#xff0c;默认不可用 1.创建一个mixin share.js export default {created() {//#ifdef MP-WEIXINwx.showShareMenu({withShareTicket: true,menus: [shareAppMessage, shareTimeline]});//#endif}, }export default {created() {//#ifde…

vs2022断点调试怎么看堆栈帧,找异常位置

打一个断点以后&#xff0c;会出现如图报错 我们要怎么找到报错的语句&#xff1f;鼠标点击->堆栈帧->上一行运行的位置->直到找到错误出错如图所示&#xff1a; 跳转到&#xff0c;我们手写的代码&#xff0c;执行出错的位置

Unity | Shader基础知识(第十二集:颜色混合)

目录 前言 一、日常生活中的常见现象 二、unity自带的一个结构体&#xff08;表面着色器SurfaceOutputStandard&#xff09; 三、自己写一个颜色混合的Shader 1.只加基础颜色Albedo 2.加入法线 3.加入光滑度 4.加入金属度 5.加入自发光 四、作者的话 前言 shader里每一…

docker安装nessus服务及使用

Nessus 是目前全世界最多人使用的系统漏洞扫描与分析软件&#xff0c;现在软件服务越来越多&#xff0c;越来越复杂&#xff0c;涉及的数据也更多&#xff1b;因此系统完成后对于系统漏洞的检测并对其进行修改十分有必要&#xff0c;本文介绍通过docker安装nessus服务及简单的使…

设计模式-模板方法模式(TemplateMethod)

1. 概念 模板方法模式是一种行为设计模式&#xff0c;它在一个方法中定义算法的骨架&#xff0c;将一些步骤延迟到子类中实现。 2. 原理结构图 2.1 图 2.2 角色 抽象类&#xff08;Abstract Class&#xff09; 定义抽象的基本操作&#xff08;Primitive Operations&#xff…

从启发式到模型化 京东推荐广告排序机制演化

1、序言&#xff1a;广告排序机制的前世今生 1.1、简介&#xff1a;广告排序机制 在线广告是国内外各大互联网公司的重要收入来源之一&#xff0c;而在线广告与传统广告最大的区别就在于其超大规模的实时竞价环境&#xff1a;数以万计的广告主在一天内可以参与亿级别的流量竞…

解决宝塔的FTP无法使用被动模式

问题&#xff1a;宝塔安装完ftp管理软件之后&#xff0c;无法使用被动模式连接 解决&#xff1a; 提示&#xff1a; 如果还是不行&#xff0c;那么要看看防火墙和安全组有没有放行被动模式的端口&#xff0c;宝塔安装的pure-ftpd软件的被动模式端口默认是39000至400…

Kubernetes 升级不弃 Docker:KubeKey 的丝滑之道

作者&#xff1a;尹珉&#xff0c;KubeSphere Ambaasador&Contributor&#xff0c;KubeSphere 社区用户委员会杭州站站长。 引言 随着 Kubernetes 社区的不断发展&#xff0c;即将迎来 Kubernetes 1.30 版本的迭代。在早先的 1.24 版本中&#xff0c;社区作出一个重要决策…

计算机网络——42攻击和对策

攻击和对策 IDS&#xff1a;入侵检测系统 分组过滤 对TCP/IP头部进行检查不检查会话间的相关性 IDS:intrusion detection system 深入分组检查&#xff1a;检查分组的内容&#xff08;e.g. 检查分组中的特征串&#xff0c;已知攻击数据库的病毒和攻击串&#xff09;检查分组间…

【网站项目】捷邻小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

FPGA - 以太网UDP通信(二)

一&#xff0c;引言 前文链接&#xff1a;FPGA - 以太网UDP通信&#xff08;一&#xff09; 在上文章中介绍了以太网简介&#xff0c;以太网UDP通信硬件结构&#xff0c;以及PHY芯片RGMII接口-GMII接口转换逻辑&#xff0c;接下来介绍UDP通信结构框图以及数据链路层&#xff…

Python | Leetcode Python题解之第28题找出字符串中的第一个匹配项的下标

题目&#xff1a; 题解&#xff1a; class Solution:def strStr(self, haystack: str, needle: str) -> int:# Func: 计算偏移表def calShiftMat(st):dic {}for i in range(len(st)-1,-1,-1):if not dic.get(st[i]):dic[st[i]] len(st)-idic["ot"] len(st)1re…

自己开发的App如何上架,详细解读App上架操作流程

对于企业或个人开发的App&#xff0c;上架是必经之路。然而&#xff0c;许多人不清楚如何进行App上架。工信部在2023年规定&#xff0c;App必须备案才能上架。那么&#xff0c;让我们一起了解App上架流程吧。 1. 准备上架所需材料 在上架App之前&#xff0c;需要准备应用图标…

类加载子系统

目录 类的加载 加载流程 类的加载器 类的链接 类的检验阶段 类的准备阶段 类的解析阶段 类的初始化 static与final的搭配问题 ()的线程安全性 类的初始化情况&#xff1a;主动使用vs被动使用 类的使用 类的卸载 类、类的加载器、类的实例之间的引用关系 类的生命…

端口协议(爆破、未授权)

常见端口服务及攻击方向&#xff1a; 弱口令爆破 工具&#xff1a;https://github.com/vanhauser-thc/thc-hydra hydra是一个支持多协议的自动化的爆破工具。 支持的服务、协议&#xff1a; telnet ftp pop3[-ntlm] imap[-ntlm] smb smbnt http-{head|get} http-{get|post}-…

深度学习入门(3)

一、感知机 感知机接收多个输入信号&#xff0c;输出一个信号。这里所说的“信号”可以想象成电流或河流那样具备“流动性”的东西。 但是&#xff0c;和实际的电 流不同的是&#xff0c;感知机的信号只有“流 / 不流”&#xff08; 1 / 0 &#xff09;两种取值。在本书中&…

【研发日记】Matlab/Simulink软件优化(一)——动态内存负荷压缩

文章目录 背景介绍 初始代码 优化代码 分析和应用 总结 背景介绍 在一个嵌入式软件开发项目中&#xff0c;有一个使用MATLAB Function编写的算法模块&#xff0c;功能是从一个较大的数组中提取一段数据&#xff0c;然后求均值输出&#xff0c;示例如下&#xff1a; 初始代…

Python和Java哪个更适合后端开发?

Python和Java都是强大的后端开发语言&#xff0c;它们各自有鲜明的特点和适用场景。选择哪一个更适合后端开发&#xff0c;主要取决于具体的项目需求、团队技术栈、个人技能偏好以及长期发展考虑等因素。 下面是两者在后端开发中的优势和劣势&#xff1a; 「Python&#xff1…

Maven超详细使用

定义 是一款用于管理和构建java项目的工具 作用 1. 依赖管理 2. 统一项目结构 3. 项目构建 项目目录结构 POM 项目对象模型 (Project Object Model) POM (Project Object Model) &#xff1a;指的是项目对象模型&#xff0c;用来描述当前的maven项目。 仓库 本地仓库&#…

银河麒麟高级服务器操作系统adb读写缓慢问题分析

1.问题环境 处理器&#xff1a; HUAWEI Kunpeng 920 5251K 内存&#xff1a; 512 GiB 整机类型/架构&#xff1a; TaiShan 200K (Model 2280K) BIOS版本&#xff1a; Byosoft Corp. 1.81.K 内核版本 4.19.90-23.15.v2101.ky10.aarch64 第三方应用 数据库 2.问题…