【Linux】简单模拟C语言文件标准库FILE

在这里插入图片描述

👦个人主页:Weraphael
✍🏻作者简介:目前正在学习c++和算法
✈️专栏:Linux
🐋 希望大家多多支持,咱一起进步!😁
如果文章有啥瑕疵,希望大佬指点一二
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注😍


目录

  • 前言
  • 一、FILE结构体设计
  • 二、fopen函数
  • 二、fwrite函数
  • 三、fflush函数
  • 四、fclose函数
  • 五、总结及相关代码

前言

在这里插入图片描述

在C语言中,FILE结构体一定封装了诸如文件描述符等字段,使得C语言文件操作的库函数可以很好的调用系统调用,因此程序员可以更加方便地使用高级接口来完成任务,而无需深入了解底层系统调用的实现细节。

这篇博客将带领大家深刻理解C语言文件操作函数底层是如何封装系统调用接口,以及C语言用户级缓冲区的现象。

注:本篇博客不是为了造一个更好的轮子,而是重在理解!!!

一、FILE结构体设计

在这里插入图片描述

(以上是库封装的FILE相关字段)

我们知道,C语言的文件操作函数底层必定会调用系统调用接口,而在往期博客中我们知道,文件相关的系统调用接口都是由文件描述符来定位文件的,因此,FILE结构体必定封装了文件描述符。

而我们这篇博客还要实现缓冲区现象,因此,FILE结构体还会封装维护缓冲区的相关字段。

在这里插入图片描述

  • _fileno:文件描述符。
  • outbuffer:输出缓冲区。需要注意的是,用户级缓冲区通常是通过动态内存分配函数(如mallocnew)在堆区分配的,大小是不固定的。
  • out_pos:当前缓冲区字符的个数。

二、fopen函数

C语言中文件打开操作fopen底层调用了系统调用接口open

在这里插入图片描述

open函数的更多详细用法请查看此篇博客:点击跳转

// fopen函数模型
FILE *fopen(const char *path, const char *mode);
// path: 文件的路径
// mode: 文件的打开方式

文件打开的方式mode有很多种,大家可以通过man手册查询,这里我重点实现以下常见的三种:

  • "w": 以只写的方式打开方式。文件不存在会自动创建,并且每打开一次都会将文件内容清空再写入。

  • "a": 以追加的方式打开文件。文件不存在会自动创建,不会对文件原有的内容做清空,而是追加写入。

  • "r": 以只读的方式打开文件,文件不存在会报错。

此外,当使用fopen函数打开文件,对于普通文件,默认情况下会使用全缓冲来刷新缓冲区,即直到缓冲区满了或者遇到'\n'才将缓冲区中的内容写入磁盘。

在这里插入图片描述

二、fwrite函数

C语言中文件写入操作fwrite底层也调用了系统调用接口write

在这里插入图片描述

write函数的更多详细用法请查看此篇博客:点击跳转

// fwrite函数模型
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
  • ptr:指向要写入的数据块的指针。通常使用void*类型的指针,可以传递任何类型的数据块。需要注意的是,ptr指向的数据必须与sizenmemb参数相对应,即size * nmemb表示要写入的总字节数。

  • size:要写入每个数据块的字节数。

  • nmemb:要写入的数据块的数量。表示要写入多少个数据块。

  • stream:指向要写入的文件的指针。需要使用标准库函数fopen()成功打开文件后,将返回的文件指针作为参数传递给fwrite()函数。

  • nmemb值充当返回值。

在这里插入图片描述

用户调用fwrite时,并不会直接将内容直接写入文件中,而是将数据写入到用户级缓冲区,然后通过一定条件,再将缓冲区的内容写入到文件中。详细步骤如下:

  1. 判断当前用户级缓冲区是否被填满。如果满了,先对缓冲区刷新,再进行后续操作。
  2. 如果遇到'\n',就将'\n'之间的字符全部刷新。
  3. 若不满足条件继续将字符往缓冲区里塞。

在这里插入图片描述

三、fflush函数

当用户调用fflush函数时,不管缓冲区是否满了还是什么,直接刷新。因此,fflush函数一定封装了系统调用接口write

// fflush函数原型
int fflush(FILE *stream);

在这里插入图片描述

四、fclose函数

fclose()函数是C语言标准库中用于关闭文件流的函数。它的作用是将缓冲区中剩余的数据写入到文件中,并释放系统资源。因此它的底层必定会调用fflush函数以及系统调用close()

int close(int fd);

在这里插入图片描述

五、总结及相关代码

  • 数据到达文件一共要执行3次拷贝,第一次是拷贝到用户级缓冲区、第二次是拷贝到系统级缓冲区、最后一次则是真正写入文件中(第二次到第三次是由操作系统帮我们完成的)。

  • 在模拟实现fwrite时,我们将一个字符一个字符拷贝到缓冲区,不满足条件,如缓冲区没有满或者没有遇到'\n'就继续拷贝至缓冲区,这不是变相减少了调用系统调用的次数,从而提高IO效率!

本篇博客相关代码:点击跳转

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java进阶学习笔记10——子类构造器

子类构造器的特点: 子类的全部构造器,都会先调用父类的构造器,再执行自己。 子类会继承父类的数据,可能还会使用父类的数据。所以,子类初始化之前,一定先要完成父类数据的初始化,原因在于&…

【Java面试】一、Redis篇(上)

文章目录 0、准备1、缓存穿透:不存在的key2、缓存击穿:热点key过期3、缓存雪崩:大批key同时过期4、双写一致性4.1 要求高一致性4.2 允许一定的一致延迟 5、面试 0、准备 Redis相关概览: 以简历上所列的项目为切入点,展…

C语言/数据结构——队列的实现

一.前言 今天我们来聊一聊数据结构的一部分——队列。今天我们主要涉及队列的基本概念结构,以及队列的基本实现。 二.正文 1.1队列 1.12队列的概念及结构 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表&#xf…

ue5 中ps使用记录贴

一、快捷键记录 放大图形 ctrlalt空格 放大图形 缩小视口 ctrl空格 ctrlD 取消选区 ctrlt缩小文字 w魔棒工具 选择魔棒的时候把容差打开的多一点 二、案例 移动文字 在相应的图层选择 移动文字 修改图片里的颜色 在通道里拷贝红色通道,复制红色通道粘贴给正常图…

【ELK日志收集过程】

文章目录 为什么要使用ELK收集日志ELK具体应用场景ELK日志收集的流程 为什么要使用ELK收集日志 使用 ELK(Elasticsearch, Logstash, Kibana)进行日志收集和分析有多种原因。ELK 堆栈提供了强大、灵活且可扩展的工具集,能够满足现代 IT 系统对…

CIM模型

CIM 是 Esri 制图信息模型。 它是一个地图内容规范,用于记录在保存、读取、引用或打开时如何永久保留描述不同项目组件的信息。 该规范以 JSON 表示,适用于 ArcGIS 应用程序和 API 中的地图、场景、布局、图层、符号和样式。 CIM 不仅限于制图设置。 要了解属性的组织方式以及…

使用vue3实现右侧瀑布流滑动时左侧菜单的固定与取消固定

实现效果 实现方法 下面展示的为关键代码,想要查看完整流程及代码可参考https://blog.csdn.net/weixin_43312391/article/details/139197550 isMenuBarFixed为控制左侧菜单是否固定的参数 // 监听滚动事件 const handleScroll () > {const scrollTopThreshol…

数据库系统基础知识

一、基本概念 二、数据库三级模式两级映像 三、数据库的分析与设计过程 四、数据模型 五、关系代数 六、数据库完整性约束 七、关系型数据库SQL简介 八、关系数据库的规范化 九、数据库的控制功能 十、数据仓库与数据挖掘基础 十一、大数据基本概念 数据库基本概念 1、数据库…

Spring 对于事务上的应用的详细说明

1. Spring 对于事务上的应用的详细说明 文章目录 1. Spring 对于事务上的应用的详细说明每博一文案2. 事务概述3. 引入事务场景3.1 第一步:准备数据库表3.2 第二步:创建包结构3.3 第三步:准备对应数据库映射的 Bean 类3.4 第四步:…

hcia datacom学习(10):交换机基础

1.二层交换机工作原理 1.1交换机的5种行为 查看mac地址表的命令为 dis mac-address *一个MAC只能关联在一个接口上,一个接口上可以学习多个MAC *mac地址漂移:mac表中,mac地址的出接口从一个端口变为另一个端口的现象。 造成mac漂移的原因…

操作系统实验四 (综合实验)设计简单的Shell程序

前言 因为是一年前的实验,很多细节还有知识点我都已经遗忘了,但我还是尽可能地把各个细节讲清楚,请见谅。 1.实验目的 综合利用进程控制的相关知识,结合对shell功能的和进程间通信手段的认知,编写简易shell程序&…

轻松拿捏C语言——【字符函数】字符分类函数、字符转换函数

🥰欢迎关注 轻松拿捏C语言系列,来和 小哇 一起进步!✊ 🌈感谢大家的阅读、点赞、收藏和关注💕 🌹如有问题,欢迎指正 感谢 目录👑 一、字符分类函数🌙 二、字符转换函数…

Spring MVC/Web

1.Spring MVC 的介绍 Spring Web MVC是基于Servlet API构建的原始Web框架,也是Spring框架的一部分。它提供了灵活可扩展的MVC架构,方便开发者构建高性能的Web应用程序,并与 Spring 生态系统无缝集成。 2.MVC 设计模式 MVC(Model…

【游戏引擎】Unity脚本基础 开启游戏开发之旅

持续更新。。。。。。。。。。。。。。。 【游戏引擎】Unity脚本基础 Unity脚本基础C#语言简介C#基础 Unity脚本基础创建和附加脚本MonoBehaviour生命周期生命周期方法 示例脚本 Unity特有的API常用Unity API 实践示例:制作一个简单的移动脚本步骤1:创建…

SpringCloud系列(30)--准备使用Hystrix的前期工作,创建服务消费者模块

前言:在上一章节中我们创建了服务提供者模块,而本节内容则是创建服务消费者模块。 1、创建一个服务提供者模块,命名为cloud-consumer-feign-hystrix-order80 (1)在父工程下新建模块 (2)选择模块的项目类型为Maven并选择模块要使用的JDK版本 …

Ansible自动化运维中的Setup收集模块应用详解

作者主页:点击! Ansible专栏:点击! 创作时间:2024年5月22日13点14分 💯趣站推荐💯 前些天发现了一个巨牛的🤖人工智能学习网站,通俗易懂,风趣幽默&#xf…

分享:怎么才能保证大数据查询的准确性?

随着大数据应用到金融风控领域,大数据越来越重要了,很多朋友在查大数据的时候都会遇到一个问题,那就是自己查询的大数据什么信息都没有,要么就是很少,这是什么原因呢?要怎么才能保证大数据查询的准确性呢?下面小编就…

WordPress搭建流程

1. 简介 WordPress 是一个 PHP 编写的网站制作平台。WordPress 本身免费,并且拥有众多的主题可以使用,适合用于搭建个人博客、公司官网、独立站等。 2. 环境准备 2.1 WordPress 下载 WordPress 可以在 Worpress中文官网 下载(如果后续要将后台调成中文的话,一定要从中文…

如何通过软件SPI读写W25Q64

STM32F1之SPI通信软件SPI代码编写-CSDN博客 目录 1. W25Qxx系列简介 2. W25Q64硬件电路 3. W25Q64框图 4. Flash操作注意事项 5. 代码编写 5.1 初始化 5.2 W25Q64读取ID号 5.3 W25Q64写使能 5.4 W25Q64等待忙 5.5 W25Q64页编程 5.6 W25Q64扇区擦除&#x…

521源码-在线客服-CRMChat网页版客服系统 UNIAPP 全方位在线客服系统源码与管理体系平台

CRMChat客服系统:基于Swoole4Tp6RedisVueMysql构建的高效沟通桥梁 CRMChat是一款独立且高性能的在线客服系统,它结合了Swoole4、Tp6、Redis、Vue以及Mysql等先进技术栈,为用户提供了卓越的在线沟通体验。该系统不仅支持在Pc端、移动端、小程…