【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.rhkb.cn/news/309888.html

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

相关文章

如何在Linux系统部署Joplin笔记并结合内网穿透实现无公网IP远程访问

文章目录 1. 安装Docker2. 自建Joplin服务器3. 搭建Joplin Sever4. 安装cpolar内网穿透5. 创建远程连接的固定公网地址 Joplin 是一个开源的笔记工具&#xff0c;拥有 Windows/macOS/Linux/iOS/Android/Terminal 版本的客户端。多端同步功能是笔记工具最重要的功能&#xff0c;…

华为数通方向HCIP-DataCom H12-821题库(多选题:321-340)

第321题 关于OSPF的命令描述,不正确的是: A、stub区域和totally stub区域配置了no-summary参数 B、OSPFv2和OSPF v3配置接口命令的区别是OSPF V2可以使用network命令,而OSPFv3直接 C、在接口上使能stubrouter命令用来配置次路由器为stub路由器,stub路由器可以与非stub路由 …

微软搭建零售新媒体创意工作室大举抢占数字营销广告市场

“微软新零售创意工作室新平台利用生成式人工智能&#xff0c;在几秒钟内轻松定制横幅广告。零售媒体预计到2026年将成为一个价值1000亿美元的行业。” 零售媒体在过去几年中发展迅速。根据eMarketerOpens在新窗口的数据&#xff0c;预计到2024年&#xff0c;仅美国的零售媒体…

【Node.js】Express学习笔记(黑马)

目录 初识 ExpressExpress 简介Express 的基本使用托管静态资源nodemon Express 路由路由的概念路由的使用 Express 中间件中间件的概念Express 中间件的初体验中间件的分类 初识 Express Express 简介 什么是 Express&#xff1f; 官方给出的概念&#xff1a;Express 是基于…

navicat远程连接mysql的异常解决-1130-2003-10061

结论&#xff1a; 1、修改数据库下root用户的host字段(为空或%) 2、修改 /etc/mysql/mysql.conf.d/mysqld.cnf 文件下 bind-address 的配置为 0.0.0.0 或者屏蔽此配置内容 (默认配置是&#xff1a; bind-address 127.0.0.1) 补充&#xff1a; 查看数据库下用户与host字段的关…

3D医疗图像配准 | 基于Vision-Transformer+Pytorch实现的3D医疗图像配准算法

项目应用场景 面向医疗图像配准场景&#xff0c;项目采用 Pytorch ViT 来实现&#xff0c;形态为 3D 医疗图像的配准。 项目效果 项目细节 > 具体参见项目 README.md (1) 模型架构 (2) Vision Transformer 架构 (3) 量化结果分析 项目获取 https://download.csdn.net/down…

【uniapp】vscode安装插件、ts校验、允许json文件注释

1、vscode安装的插件&#xff1a; uni-create-viewuni-hlperuniapp小程序扩展 2、ts校验 安装插件&#xff1a; pnpm i -D types/wechat-miniprogram uni-helper/uni-app-types配置tsconfig.json {"extends": "vue/tsconfig/tsconfig.json","compi…

内核是如何接收⽹络包的?

应用层做的那么舒服&#xff0c;为什么还要去看驱动和内核&#xff1f; “工作了四五年&#xff0c;并不是有4-5年经验&#xff0c;⽽是⼯作了4-5年⽽已” 引言 Linux里最重要的一个模块-网络模块,用简单的udp来举例&#xff0c;下图是我在大学的时候的基于linux的socket网络…

顶顶通呼叫中心中间件(mod_cti基于FreeSWITCH)-回铃音补偿

文章目录 前言联系我们解决问题操作步骤 前言 回铃音&#xff1a; 当别人打电话给你时&#xff0c;你的电话响铃了&#xff0c;而他听到的声音叫做回铃音。回铃音是被叫方向主叫方传送&#xff0c;也是彩铃功能的基础。我们平时打电话听到的“嘟 嘟 嘟 嘟”的声音&#xff0c;就…

mysql 查询实战-变量方式-解答

对mysql 查询实战-变量方式-题目&#xff0c;进行一个解答。&#xff08;先看题&#xff0c;先做&#xff0c;再看解答&#xff09; 1、查询表中⾄少连续三次的数字 1&#xff0c;处理思路 要计算连续出现的数字&#xff0c;加个前置变量&#xff0c;记录上一个的值&#xff0c…

postgresql uuid

示例数据库版本PG16&#xff0c;对于参照官方文档截图&#xff0c;可以在最上方切换到对应版本查看&#xff0c;相差不大。 方法一&#xff1a;自带函数 select gen_random_uuid(); 去掉四个斜杠&#xff0c;简化成32位 select replace(gen_random_uuid()::text, -, ); 官网介绍…

LoRa无线电机温振传感器,FlexLua低代码技术助力快速实现。

在物联网时代&#xff0c;无线传感技术的应用愈发广泛。其中&#xff0c;LoRa&#xff08;长距离低功耗无线技术&#xff09;作为一种适用于远距离、低功耗的通信技术&#xff0c;被广泛应用于各种物联网场景。而结合温度和振动传感技术&#xff0c;能够构建出用于监测机器状态…

pytest-yaml-sanmu(二):使用hook自定义yaml用例的执行方式

前言 本文抛砖引玉&#xff0c;通过以下几个测试框架的封装示例&#xff0c;一步步引导你实现属于自己的 yaml 测试框架&#xff1a; 加法测试 计算测试 接口测试 Web 测试 使用本插件需要对 Python 和 Pytest 较为熟练的应用经验&#xff0c;本文认为你已经具备这些条件。…

HTTP协议名词解释

一、HTTP协议通讯名词解释-URL URL(Uniform Resource Locator&#xff0c;统一资源定位符)是标识Web资源的唯一标识符。通过它即可获取其标识的资源。 最常用的URL格式如下: protocol://hostname[:port]/[path/Ifile[?paramvaluel 这个结构中有几个部分是可选的。如果端口…

Python数学建模学习-PageRank算法

1-基本概念 PageRank算法是由Google创始人Larry Page在斯坦福大学时提出&#xff0c;又称PR&#xff0c;佩奇排名。主要针对网页进行排名&#xff0c;计算网站的重要性&#xff0c;优化搜索引擎的搜索结果。PR值是表示其重要性的因子。 中心思想&#xff1a; 数量假设&#…

10kV配电室在线监控改造技术方案

安科瑞薛瑶瑶18701709087 摘要&#xff1a;目前&#xff0c;我国经济高速发展&#xff0c;社会在不断进步&#xff0c;国家加大了农村低压配电网络改造升级投入&#xff0c;低压配电网供电可靠性及供电质量得到明显提升&#xff0c;但低压配电网络自动化运维水平及农村电网用电…

如何使用Docker部署WPS Office服务并实现无公网IP远程处理文档表格

文章目录 1. 拉取WPS Office镜像2. 运行WPS Office镜像容器3. 本地访问WPS Office4. 群晖安装Cpolar5. 配置WPS Office远程地址6. 远程访问WPS Office小结 7. 固定公网地址 wps-office是一个在Linux服务器上部署WPS Office的镜像。它基于WPS Office的Linux版本&#xff0c;通过…

移动开发避坑指南——内存泄漏

在日常编写代码时难免会遇到各种各样的问题和坑&#xff0c;这些问题可能会影响我们的开发效率和代码质量&#xff0c;因此我们需要不断总结和学习&#xff0c;以避免这些问题的出现。接下来我们将围绕移动开发中常见问题做出总结&#xff0c;以提高大家的开发质量。本系列文章…

【Qt编译】ARM环境 Qt5.14.2-QtWebEngine库编译 (完整版)

ARM 编译Qt5.14.2源码 1.下载源码 下载Qt5.14.2源代码&#xff08;可根据自己的需求下载不同版本&#xff09; 下载网站&#xff1a;https://download.qt.io/new_archive/qt/5.14/5.14.2/single/ 2.相关依赖(如果需要的话) 先参考官方文档的需求进行安装&#xff1a; 官方…

第十五届蓝桥杯省赛C/C++大学B组真题及赛后总结

目录 个人总结 C/C 组真题 握手问题 小球反弹 好数 R 格式 宝石组合 数字接龙 爬山 拔河 ​编辑 再总结及后续规划 个人总结 第一次参加蓝桥杯&#xff0c;大二&#xff0c;以前都在在学技术&#xff0c;没有系统的学过算法。所以&#xff0c;还是花了挺多时间去备…