Linux——用户级缓存区及模拟实现fopen、fweite、fclose
linux基础io重定向-CSDN博客
文章目录
目录
文章目录
什么是缓冲区
为什么要有缓冲区
二、编写自己的fopen、fwrite、fclose
1.引入函数
2、引入FILE
3.模拟封装
1、fopen
2、fwrite
3、fclose
4、fflush
总结
前言
用快递站讲述缓冲区
收件区(类比输入缓冲区):
快递站的收件区就如同计算机的输入缓冲区。当快递员不断送来包裹(好比计算机从外部设备接收数据),收件区先把这些包裹暂存起来。就像计算机通过输入设备(如键盘输入字符、网络传来数据等)接收到的数据,不会立刻被全部处理,而是先放在输入缓冲区。例如,很多快递在一天内不同时段被送来,收件区堆积着这些待进一步处理的包裹,这类似输入缓冲区存放着源源不断接收到的数据,等待后续的处理步骤。
分拣区(类比处理缓冲区):
这里可比作计算机的处理缓冲区。在快递站分拣区,工作人员会对包裹进行查看、分类(依据目的地等信息),这类似计算机处理缓冲区对暂存的数据进行分析、判断处理方式。比如要确定数据该送往哪个程序或存储区域进行下一步操作,就如同分拣区确定包裹该发往哪个派送点。而且有时候包裹会在分拣区排队等待进一步转运安排,这也如同数据在处理缓冲区可能会因处理资源不足等原因排队等待处理,以确保按正确顺序完成处理。
发件区(类比输出缓冲区):
快递站的发件区就像计算机的输出缓冲区。分拣好准备发往各个派送点的包裹会在发件区暂存(如同计算机处理好的数据在输出缓冲区暂存),等待快递车辆来运走(类似等待合适时机输出到外部设备)。比如一批要发往同一区域的包裹先在发件区集合,就如同一组要输出到显示器显示的数据先在输出缓冲区等待统一发送以便正确显示。同时,发件区工作人员要协调快递车辆到来时间等,保证包裹有序发出,这类似输出缓冲区要协调与外部设备的连接及数据传输时机,确保数据准确输出到目标设备。
总之,快递站的不同区域通过暂存、处理、再暂存并协调输出的流程,很好地模拟了计算机缓冲区在接收、处理、输出数据过程中的作用。
一、缓冲区是什么?
缓冲区是计算机存储体系中的一个特定区域,主要起到暂存数据的作用。
在输入方面:
当外部设备(如键盘、鼠标、网络等)向计算机输入数据时,数据不会立刻被计算机核心部件(如CPU)处理,而是先进入输入缓冲区暂存。比如你通过键盘快速打字,字符数据会先堆积在输入缓冲区,等待后续按合适的速度和顺序被处理,避免因输入速度过快而导致数据丢失或处理混乱。
在输出方面:
当计算机内部处理好的数据要输出到外部设备(如显示器、打印机等)时,也会先暂存到输出缓冲区。例如计算机要在显示器上显示一幅图像,处理好的图像数据会先放在输出缓冲区,然后再按照显示器的刷新频率等要求,适时且有序地将数据传输到显示器进行显示,这样能保证输出的稳定性和连贯性。
在数据处理过程中:
有时数据在不同部件(如CPU和内存之间、不同程序之间等)流转时,也会在中间设置缓冲区来暂存数据,起到协调数据传输速度差异、避免数据冲突等作用。
总之,缓冲区就像是数据流转过程中的一个个“临时仓库”,让数据的输入、输出和处理都能更顺畅、有序地进行。
什么是缓冲区
缓冲区本质上一块内存区域,用来保存临时数据。缓冲区在各种计算任务中都广泛应用,包括输入/输出操作、网络通信、图像处理、音频处理等。
这块内存区域是由谁提供的呢,缓冲区在哪里呢?可以继续向下看.
这里先告诉答案,是C标准库提供的.
为什么要有缓冲区
缓冲区用于解决数据传输速度不匹配或不稳定的问题,并提高数据处理的效率。
当从硬盘读取大量数据时,将数据直接传输到内存中可能会导致读写速度不匹配(内存速度快,而硬盘读取速度慢,这是相对来说的),从而导致性能瓶颈。为了缓解这个问题,可以引入一个缓冲区,先将一部分数据读取到缓冲区中,然后再从缓冲区逐步读取数据到内存中,以平衡数据传输速度。
这里有个很合适的例子来解释:
例如你和你的朋友在两个不同的大学,相差大概500公里,有一天你想送一些书给你的朋友,此时你可以选择骑自行车,亲自骑行去送这些书,礼轻情意重嘛,加上中途休息,然后由于速度慢,花了大概一周的时间才到,送了之后然后又骑回自己的学校,又花了一周的时间,一共过了两周完整的工作才完成,耗时太长。
假设此时你学聪明了,既然那么慢,那么直接坐高铁去送,可来回一共都500多了,这都比这些书的价值多了,即成本太高了.
可以把以上这些书看做资源,这种模式叫做写透模式.
此时你想到,可以寄快递来送这些书啊,价格便宜,而且两三天就到了,这多实惠,于是你把这些书交给了顺丰 快递,过了两三天,你的朋友在手机上给你说,说我收到这些书了,然后这样就成功的把资源交到了对方的手中。这个顺丰快递在这里扮演的角色便是缓冲区.
顺丰 拿到你的快递也不是立马就送,而是等待数量足够多时,再一次性开始运输,这相当于是一种缓冲区的刷新策略.
缓冲区刷新策略
刷新策略主要有以下3种:
1.立即刷新
2.行刷新(行缓冲),遇到\n刷新
3.满刷新(全缓冲),指的是将输入或输出的数据完全存储在缓冲区中,然后再进行传输或处理。
当然也会有一些特殊情况:
1.用户强制刷新(fflush)
2.进程退出
遇到以上两种情况时,必须马上从刷新缓冲区的数据,而不要按照之前的刷新策略继续等待.
所以缓冲策略 = 一般情况 + 特殊情况.
一般而言,行缓冲的设备文件 --- 显示器
全缓冲的设备文件 --- 磁盘文件
但所有的设备,永远倾向于全缓冲 --> 缓冲区满了再刷新 --> 需要更少次数的IO操作 -->更少次数的外设访问(相当于提高了整机效率).
有同学可能有疑问,比如10行数据,每一行有100个字节,虽然10行最后再一起刷新,只进行了一次的外设访问,但是数据量很多啊,1000个字节,而按行刷新虽然刷新了10次,但每次数据量少啊,那为什么外设访问次数越少越好呢?
这是因为和外部设备IO的时候,数据量的大小不是主要矛盾,你和外设预备IO的过程是最耗费时间的.
比如你和别人借钱,往往沟通的过程要耗费很长时间,而转账的过程只需要几秒,这同样的道理.
那我们直接改成全缓冲不就行了吗?这样效率不就高了吗,还要什么行缓冲.
其实这些策略,都是根据实际情况做的妥协:
例如行缓冲就是针对于显示器,是给用户看的,一方面要照顾效率,另一方面也要照顾用户体验.
而平常我们打开的一些文本文件便是全缓冲,等到用户全部写完再一次性进行保存.
有了这些缓冲区和策略,便可以提高数据处理的效率.
二、编写自己的fopen、fwrite、fclose
1.引入函数
这些函数都是3好手册的函数,也就是说这些函数可以有2好手册的系统函数来封装。
2、引入FILE
在之前的语言学习时,我们知道“->"引用通常都是结构体,那么stdin、stdout、stderr这三个流也就是结构体了。
因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访 问的。
所以C库当中的FILE结构体内部,必定封装了fd。
man 3 stdin,我们可以看到他们的类型。
编辑
那么FILE又是什么类型呢?
打开头文件找到EILE类
3.模拟封装
我们想要实现一个文件的打开,写入和关闭文件操作的函数。
#include"myfile.h"
#define myfile "test.txt"
int main()
{//打开文件_FILE* _fd= _fopen(myfile,"a");if(_fd==NULL)return 1;//读文件const char*ptr="hello linux!!\n";//size_t _fwrite(ptr,strlen(ptr),_fd);int cnt = 10;while(cnt){_fwrite(ptr, strlen(ptr),_fd);// fflush(fp);sleep(1);cnt--;}//写关闭文件_fclose(_fd); return 0;
}
我们现在就来实现这个几个函数内部封装。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>#include <string.h>#define SIZE 1024
#define FILE_MODE 0666
#define FLUSH_NOW 1
#define FLUSH_LINE 2
#define FLUSH_ALL 4typedef struct _FILE_IO
{int fileno;int flag; //char inbuffer[SIZE];//int in_pos;char outbuffer[SIZE]; // 用一下这个int out_pos;
}_FILE;_FILE* _fopen(const char*path,const char* made);
size_t _fwrite(const char*ptr,size_t size,_FILE* _stream);
int _fclose(_FILE*_stream);
1、fopen
_FILE* _fopen(const char*path,const char* made)
{assert(path);assert(made);int fd=-1;int f=0;if(strcmp(made, "w") == 0) {f = (O_CREAT|O_WRONLY|O_TRUNC);fd = open(path, f, FILE_MODE);}else if(strcmp(made, "a") == 0) {f = (O_CREAT|O_WRONLY|O_APPEND);fd = open(path, f, FILE_MODE);}else if(strcmp(made, "r") == 0) {f = O_RDONLY;fd = open(path, f);}else return NULL;if(fd == -1) return NULL;_FILE *fp = (_FILE*)malloc(sizeof(_FILE));if(fp == NULL) return NULL;fp->fileno = fd;//fp->flag = FLUSH_LINE;fp->flag = FLUSH_ALL;fp->out_pos = 0;return fp;
}
2、fwrite
size_t _fwrite(const char*ptr,size_t size,_FILE* _stream)
{memcpy(&_stream->outbuffer[_stream->out_pos], ptr, size); // 没有做异常处理, 也不考虑局部问题_stream->out_pos += size;if(_stream->flag&FLUSH_NOW){write(_stream->fileno, _stream->outbuffer, _stream->out_pos);_stream->out_pos = 0;}else if(_stream->flag&FLUSH_LINE){if(_stream->outbuffer[_stream->out_pos-1] == '\n'){ // 不考虑其他情况write(_stream->fileno, _stream->outbuffer, _stream->out_pos);_stream->out_pos = 0;}}else if(_stream->flag & FLUSH_ALL){if(_stream->out_pos == SIZE){write(_stream->fileno, _stream->outbuffer, _stream->out_pos);_stream->out_pos = 0;}}return size;
}
3、fclose
int _fclose(_FILE*_stream)
{if(_stream == NULL) return -1;int fd=_stream->fileno;_fflush(_stream);close(fd);free(_stream);return fd;}
4、fflush
void _fflush(_FILE *fp)
{if(fp->out_pos > 0){write(fp->fileno, fp->outbuffer, fp->out_pos);fp->out_pos = 0;}
}
完整代码
总结
缓冲区位于用户程序和硬件设备之间,用来缓存数据,目的是让快速的 CPU 不必等待慢速的输入输出设备,同时减少操作硬件的次数。对于 IO 密集型的网络应用程序(如网站、数据库、DNS、CDN 等),缓冲区的设计至关重要,它能十倍甚至一百倍得提高程序性能。
关于缓冲区还有更多的内容,将在 “文件操作” 一章中深入讲解
相关文章:
Linux——用户级缓存区及模拟实现fopen、fweite、fclose
linux基础io重定向-CSDN博客 文章目录 目录 文章目录 什么是缓冲区 为什么要有缓冲区 二、编写自己的fopen、fwrite、fclose 1.引入函数 2、引入FILE 3.模拟封装 1、fopen 2、fwrite 3、fclose 4、fflush 总结 前言 用快递站讲述缓冲区 收件区(类比输…...
视觉感知与处理:解密计算机视觉的未来
文章目录 前言1. 计算机视觉的概述2. 计算机视觉的应用3. 运动感知与光流4. 人类视觉感知4.1 大脑中的视觉处理4.2 视觉缺陷与对比4.3 分辨率4.4 视觉错觉5. 图像采集与处理6. 图像处理流程7. 二值图像处理与分割8. 3D 机器视觉系统8.1 主动3D视觉8.2 立体视觉9. 商业机器视觉系…...
【大数据学习 | Spark-Core】广播变量和累加器
1. 共享变量 Spark两种共享变量:广播变量(broadcast variable)与累加器(accumulator)。 累加器用来对信息进行聚合,相当于mapreduce中的counter;而广播变量用来高效分发较大的对象,…...
postgresql按照年月日统计历史数据
1.按照日 SELECT a.time,COALESCE(b.counts,0) as counts from ( SELECT to_char ( b, YYYY-MM-DD ) AS time FROM generate_series ( to_timestamp ( 2024-06-01, YYYY-MM-DD hh24:mi:ss ), to_timestamp ( 2024-06-30, YYYY-MM-DD hh24:mi:ss ), 1 days ) AS b GROUP BY tim…...
pywin32库 -- 读取word文档中的图形
文章目录 前置操作解析body中的图形解析页眉中的图形 前置操作 基于pywin32打开、关闭word应用程序; import pythoncom from win32com.client import Dispatch, GetActiveObjectdef get_word_instance():""" 获取word进程 实例"""py…...
GitLab使用示例
以下是从 新建分支开始,配置 GitLab CI/CD 的完整详细流程,涵盖每个步骤、配置文件路径和具体示例。 1. 新建分支并克隆项目 1.1 在 GitLab 上创建新分支 登录 GitLab,进入目标项目页面。依次点击 Repository > Branches。点击右上角 Ne…...
uniapp echarts tooltip formation 不识别html
需求: echarts 的tooltip 的域名太长,导致超出屏幕 想要让他换行 思路一: 用formation自定义样式实现换行 但是: uniapp 生成微信小程序, echart种的tooltip 的formation 识别不了html ,自定义样式没办…...
3D扫描对文博行业有哪些影响?
三维扫描技术对文博行业产生了深远的影响,主要体现在以下几个方面: 一、高精度建模与数字化保护 三维扫描技术通过高精度扫描设备,能够捕捉到文物的每一个细节,包括形状、纹理、颜色等,从而生成逼真的3D模型。这些模…...
面试(十一)
目录 一.IO多路复用 二.为什么有IO多路复用机制? 三.IO多路复用的三种实现方式 3.1 select select 函数接口 select 使用示例 select 缺点 3.2 poll poll函数接口 poll使用示例 poll缺点 3.3 epoll epoll函数接口 epoll使用示例 epoll缺点 四. 进程和线程的区别…...
React-useState的使用
useState 是 React 提供的一个 Hook,允许你在函数组件中添加和管理状态(state)。在类组件中,状态管理通常是通过 this.state 和 this.setState 来实现的,而在函数组件中,useState 提供了类似的功能。 基本…...
设计模式之破环单例模式和阻止破坏
目录 1. 序列化和反序列化2. 反射 这里单例模式就不多说了 23种设计模式之单例模式 1. 序列化和反序列化 这里用饿汉式来做例子 LazySingleton import java.io.Serializable;public class LazySingleton implements Serializable {private static LazySingleton lazySinglet…...
11.19c++面向对象+单例模式
编写如下类: class File{ FILE* fp }; 1:构造函数,打开一个指定的文件 2:write函数 向文件中写入数据 3:read函数,从文件中读取数据,以string类型返回 代码实现: #include <iostream>using namespace std;class…...
一文了解TensorFlow是什么
TensorFlow是一个开源的机器学习框架,由Google开发并维护。它提供了一个灵活且高效的环境,用于构建和训练各种机器学习模型。 TensorFlow的基本概念包括: 张量(Tensor):TensorFlow中的核心数据结构&#x…...
如何做好一份技术文档?
打造出色技术文档的艺术 在当今技术驱动的世界中,技术文档扮演着至关重要的角色。它不仅是工程师和开发人员之间交流的桥梁,更是产品和技术成功的隐形推手。一份优秀的技术文档宛如一张精准的航海图,能够引导读者穿越技术的迷雾,…...
Linux和Ubuntu的关系
Linux和Ubuntu的关系: 1. Linux本身是内核,Ubuntu系统是基于Linux内核的操作系统。 2. Linux内核操作系统的构成: 内核、shell、文件系统、应用程序 -应用程序:文本编辑器等 -文件系统:文件存放在存储设备上的组织方…...
软件工程之静态建模
静态模型:有助于设计包、类名、属性和方法特征标记(但不是方法体)的定义,例如UML类图。 用例的关系: 扩展关系: 扩展关系允许一个用例(可选)扩展另一个用例(基用例&…...
PICO VR串流调试Unity程序
在平时写Unity的VR程序的时候,需要调试自己写的代码,但是有的时候会发现场景过于复杂,不是HMD一体机能运行的,或者为了能够更方便的调试,不需要每次都将程序部署到眼睛里,这样非常浪费时间,对于…...
自媒体图文视频自动生成软件|03| 页面和结构介绍
代码获取方式在文本末尾🔚 *代码获取方式在文本末尾🔚 *代码获取方式在文本末尾🔚 *代码获取方式在文本末尾🔚 视频图片生成器 一个基于 Python 和 Web 的工具,用于生成带有文字和语音的视频以及图片。支持多种尺寸、…...
深入浅出摸透AIGC文生图产品SD(Stable Diffusion)
hihi,朋友们,时隔半年(24年11月),终于能腾出时间唠一唠SD了🤣,真怕再不唠一唠,就轮不到SD了,技术更新换代是在是太快! 朋友们,最近(24年2月)是真的没时间整理笔记,每天都在疯狂的学习Stable Diffusion和WebUI & ComfyUI,工作实在有点忙,实践期间在飞书上…...
解析生成对抗网络(GAN):原理与应用
目录 一、引言 二、生成对抗网络原理 (一)基本架构 (二)训练过程 三、生成对抗网络的应用 (一)图像生成 无条件图像生成: (二)数据增强 (三ÿ…...
CodeIgniter URL结构
CodeIgniter 的URL 结构设计得简洁且易于管理。通常遵循以下模式: http://<domain>/<index_page>/<controller>/<method>/<parameters> 下面是每个部分的详细说明: <domain>: 这是你的网站域名&#…...
从 App Search 到 Elasticsearch — 挖掘搜索的未来
作者:来自 Elastic Nick Chow App Search 将在 9.0 版本中停用,但 Elasticsearch 拥有你构建强大的 AI 搜索体验所需的一切。以下是你需要了解的内容。 生成式人工智能的最新进展正在改变用户行为,激励开发人员创造更具活力、更直观、更引人入…...
鸿蒙本地模拟器 模拟TCP服务端的过程
鸿蒙模拟器模拟TCP服务端的过程涉及几个关键步骤,主要包括创建TCPSocketServer实例、绑定IP地址和端口、监听连接请求、接收和发送数据以及处理连接事件。以下是详细的模拟过程: **1.创建TCPSocketServer实例:**首先,需要导入鸿蒙…...
Qt/C++基于重力模拟的像素点水平堆叠效果
本文将深入解析一个基于 Qt/C 的像素点模拟程序。程序通过 重力作用,将随机分布的像素点下落并水平堆叠,同时支持窗口动态拉伸后重新计算像素点分布。 程序功能概述 随机生成像素点:程序在初始化时随机生成一定数量的像素点,每个…...
Zookeeper学习心得
本人学zookeeper时按照此文路线学的 Zookeeper学习大纲 - 似懂非懂视为不懂 - 博客园 一、Zookeeper安装 ZooKeeper 入门教程 - Java陈序员 - 博客园 Docker安装Zookeeper教程(超详细)_docker 安装zk-CSDN博客 二、 zookeeper的数据模型 ZooKeepe…...
嵌入式开发工程师面试题 - 2024/11/24
原文嵌入式开发工程师面试题 - 2024/11/24 转载请注明来源 1.若有以下定义语句double a[8],*pa;int i5;对数组元素错误的引用是? A *a B a[5] C *(p1) D p[8] 解析: 在 C 或 C 语言中&am…...
Python中打印当前目录文件树的脚本
效果图: 实现脚本: 1、显示所有文件和文件夹: import osdef list_files(startpath, prefix):items os.listdir(startpath)items.sort()for index, item in enumerate(items):item_path os.path.join(startpath, item)is_last index le…...
全景图像(Panorama Image)向透视图像(Perspective Image)的跨视图转化(Cross-view)
一、概念讲解 全景图像到透视图像的转化是一个复杂的图像处理过程,它涉及到将一个360度的全景图像转换为一个具有透视效果的图像,这种图像更接近于人眼观察世界的方式。全景图像通常是一个矩形图像,它通过将球面图像映射到平面上得到…...
Redis 中的 hcan 命令耗内存,有什么优化的方式吗 ?
Redis 中的 hcan 命令耗内存,有什么优化的方式吗 ? 1. 使用合适的游标值:2. 控制每次迭代返回的键数量:3. 避免长时间运行的迭代:4. 使用HSCAN与SCAN命令结合:5. 优化哈希表结构:6. 监控和调整R…...
豆包MarsCode算法题:三数之和问题
问题描述 思路分析 1. 排序数组 目的: 将数组 arr 按升序排序,这样可以方便地使用双指针找到满足条件的三元组,同时避免重复的三元组被重复计算。优势: 数组有序后,处理两个数和 target - arr[i] 的问题可以通过双指针快速找到所有可能的组…...
荣耀手机商城官方网站/优化seo深圳
这两者最简单明了的区别就是: 打造全网web前端全栈资料库(总目录)看完学的更快,掌握的更加牢固,你值得拥有(持续更新) 静态页面是不能随时改动的,静态是一次性写好放在服务器上进行浏…...
建设银行网站网址/百度seo关键词排名查询工具
文章目录一、核心组件1.1 SecurityContextHolder类1.1.1 概念1.1.2 存储策略1.1.3 源码1.2 SecurityContext接口1.3 Authentication接口1.4 GrantedAuthority接口1.5 UserDetails接口1.6 UserDetailsService接口1.7 AuthenticationManager接口1.8 DaoAuthenticationProvider二、…...
wordpress集成文库插件/seo优化包括哪些
一、学生背景学生姓名 : 韦同学成绩概况 : 绩点 2.7所学专业 : Computer science就读学校 : 明尼苏达录取专业 : informationtechnology留学层级 : 硕士录取结果 : 悉尼大学*二、申请诊断分析优…...
网站做一样算不算侵权/泰州网站排名seo
概述 HummerRisk 是开源的云原生安全平台,以非侵入的方式解决云原生环境的安全和治理问题。核心能力包括混合云的安全治理和容器云安全检测。 本文将介绍HummerRisk中的操作审计部分功能,包括如何如何同步云事件、云事件分析、云事件聚合查询、源IP分析…...
网站编辑转行做文案/软件培训
前言 很多朋友问我的博客是什么软件写的,嘻嘻,其潜台词是我的博客页面还挺好看的呢!!!心里美滋滋的,这里就把方法共享出来吧 定制样式而已 我的博客主要是对H1的样式做了一点改变,给H1加上了背景…...
免费自助音乐网站申请/百度seo排名软
题库来源:安全生产模拟考试一点通公众号小程序 安全生产模拟考试一点通:茶艺师(中级)考试内容是安全生产模拟考试一点通总题库中生成的一套茶艺师(中级)考试总结,安全生产模拟考试一点通上茶艺…...