当前位置: 首页 > news >正文

Linux——缓冲区

我在上篇博客留下了一个问题,那个问题就是关于缓冲区的问题,我们发现
文件有缓冲区,语言有用户级缓冲区,那么缓冲区到底是什么?,或者该怎
么认识缓冲区?这篇文章或许会让你有所认识,并且在此之前我还会介绍文
件的结构体对象中的成员。

文章目录

    • 标准错误
    • 文件结构体
  • 1. 缓冲区
    • a. 引入
    • b. 缓冲区存在的意义
    • c. 产生的问题
    • d. C语言提供的缓冲区
  • 2. 尝试实现一个用户缓冲区

但是在此之前,我要补充两个知识点,一个是为什么要有标准错误,而且标准错误也是指向屏幕。还有就是介绍内核数据结构文件结构体。

标准错误

很多人都知道一个进程会默认打开三个文件标准输入,标准输出,标准错误,其中标准输入指键盘,标准输出和标准错误都是指屏幕。我们对标准输入和标准输出很熟悉,基本上每个人都使用过,但是标准错误我们可能没有用过,那么它是什么?以及为什么要有它?
它是一个文件,其实正如它的名字而言,它是记录进程错误信息的文件,那么这个文件可以是屏幕,那自然也可以是一个文本文件。像我们使用过的perror就是输出到标准错误:
在这里插入图片描述
只是我们的默认标准错误指向屏幕而已,当我们把标准错误的指向修改后:
在这里插入图片描述
在这里插入图片描述
这后面的Sucess是C语言中错误码对应的错误信息,当我们修改错误码之后:
在这里插入图片描述
在这里插入图片描述
所以标准错误可以帮助我们在进行大型的工程的时候,通过改变标准错误指向的方式将错误信息写入到特定文本文件以等待后续的处理,而正常的信息则是正常写到自己的目标文件(屏幕)里,互不干扰。

文件结构体

我们说当一个文件被打开时操作系统会创建一个结构体来描述这个文件,那现在我们就来简单认识一下该结构体中的一些成员:
在这里插入图片描述
其中f_list是用来链接系统中被打开文件的。
f_count是有多少个进程打开了文件
f_flags是文件的打开方式
f_mode是文件的权限
f_fowner是说明文件是谁打开的
f_pos表示文件的读写位置
f_mapping跟文件缓冲区有关
f_op是关于对文件操作的操作集:
在这里插入图片描述

1. 缓冲区

我们接下来的缓冲区不做特殊说明说的都是用户级别的缓冲区

a. 引入

我们现在再回顾这个问题:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们看到,有没有fflush,会产生出不同的结果,但是为什么第一份代码中为什么aaaaaaaa没有输入到log.txt文件中呢?这就是我们今天要说的缓冲区。这是因为write是系统调用,它写入内容到一号文件时,是直接写入到文件缓冲区中,而printf是C标准库提供的函数,它会先将内容输入到C语言提供的缓冲区中,但是我们知道,C语言缓冲区中的内容不做处理的话是直到程序运行结束的时候才会刷新,而我们在程序结束之前就将log.txt文件关闭了,那缓冲区中的aaaaaaaaa就被释放了。我们也平常会说斜杠n刷新缓冲区,但是缓冲区到底是什么呢?其实缓冲区就是平台(C语言、操作系统)提供的一块内存而已。

b. 缓冲区存在的意义

那么缓冲区存在的意义是什么呢?我们直接将内容打印到屏幕上不可以吗?当然是可以的,屏幕也是文件,当我们使用系统调用的时候会越过C语言提供的缓冲区,直接写到屏幕上。
首先,我们要对文件进行写入,本质上其实是对硬件的写入,那么假如当我们高频的对硬件进行读写的时候,那势必会将我们程序的运行速度减慢,那么这时侯,缓冲区的作用就来了,我们可以先将对文件的读写操作先写入到这个缓冲区中,然后就不用管它了,而这个缓冲区只需要以一种特定的触发方式,当触发之后再将内容写入到文件中。这么做的话就会分担我们程序的压力,从而提高我们程序的效率。写入文件的动作是必须做的,但是看的就是调取硬件的频率。
并且缓冲区中的触发机制,是缓冲区中的数据积累到一定量的时候,就会触发,从而向文件中写入,不需要多次向文件中写入,那么这也帮我们降低了写入文件的成本,从而变相的提高了我们写入文件的效率
其中的触发机制,就是我们的缓冲区的刷新机制,而缓冲区的刷新机制一般有:
即时缓冲(立即刷新)、行缓冲(行刷新)、全缓冲(缓冲区满了再刷新)。
当然也会有特殊情况:
强制刷新(fflush)、进程退出的时候自动刷新
而对于硬件而言一般来说:
显示器采用的是行刷新,磁盘采用的是全刷新

c. 产生的问题

我们会有这样的一份代码:
在这里插入图片描述
在这里插入图片描述
我们看到,当程序正常运行的时候,结果是符合我们预期的,但是当它重定向到文件的时候,文件中的内容不符合我们的预期。观察它会发现,C标准库的函数打印的内容打印了两份,而系统调用只打印了一份且顺序有所变化。
那么接下来我就带大家分析其中的原因:
程序正常运行我们就不说了,我们只说重定向的问题。
当我们重定向程序打印的内容到文件的时候,其实有一个东西偷偷的改变了,那就是缓冲区的刷新机制,由屏幕缓冲区的刷新到硬盘的刷新机制,而这也是行缓冲到全缓冲的变化。全缓冲(缓冲区是很大的)意味着不强制刷新的情况下,这一点内容是只有进程结束的时候才会刷新缓冲区内容,要注意我们在程序结束之前可是创建了一个子进程父子进程是共享代码数据的,现在就要有一个认识:用户级缓冲区也是属于进程的一份数据,那么缓冲区中的数据父子共享。所以无论父子进程哪个进程先退出,都会将自己缓冲区的内容刷新到文件中,那缓冲的内容是共享的啊,其中一个刷走之后,另一个就没有了,不合理,所以这里会发生写时拷贝,使另一个没有退出的进程仍然享有缓冲区的数据,那这时候,该进程也退出了,也要刷新缓冲区了,这时候会再次向文件中写入数据,而这就是导致重定向的时候C标准库的函数打印了两次的原因,那为什么系统调用没有打印两次呢?那是因为系统调用是直接向文件中写入的,没有经过C语言的缓冲区,也就不是我们程序的数据它已经是操作系统的数据了,不触发写时拷贝,所以就打印一次。
还有是顺序问题,这个很简单:
对于直接运行程序,由于是输出到屏幕,每一个输出的内容又都有斜杠n,所以打印的内容都是即时刷新到文件中了。
对于重定向,由于是全缓冲,系统调用不管直接刷到文件里了,而C标准库的函数还在C语言提供的缓冲区里。所以才会导致顺序发生变化。
在这里插入图片描述
而上面的向文件中写入也只是先写入到文件缓冲区中,然后由操作系统来根据自己的刷新缓冲区的触发机制来刷新缓冲区。
还有一个动词我们要明确,什么是刷新
刷新就是将缓冲区的内容写入到目的地的过程,比如将C语言提供的缓冲区中的内容写到文件缓冲区中,又或者是操作系统将文件缓冲区中的内容写入到磁盘文件中。
而C语言提供的缓冲区这种我们一般就叫做用户缓冲区
上面说的文件缓冲区是属于操作系统的,属于内核缓冲区

d. C语言提供的缓冲区

那么如果上面说的C语言给我们提供了缓冲区的话,它在哪里呢?
我们观察C标准库的关于文件操作的接口就会发现:
在这里插入图片描述
这个缓冲区其实就在FILE结构体里:
在这里插入图片描述
在这里插入图片描述

可以看到,C标准库中的FILE确实是维护着一段空间。

2. 尝试实现一个用户缓冲区

经过上面的探究,我们也试着写出一个属于自己的简单的用户级别的缓冲区,用户级别的缓冲区肯定是封装着系统调用。
头文件

#pragma oncetypedef struct myFILE
{int _fileno; //存储fdchar _buffer[1024]; //用户缓冲区int _end;//缓冲区的最后一个元素的后一个元素的下标
}myFILE;extern myFILE* my_fopen(const char* path, const char* mode);
extern int my_fputs(const char* s, myFILE* stream);
extern int my_fflush(myFILE* stream);
extern int my_fclose(myFILE* fp);

原文件

#include "mylib.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>  
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>myFILE* my_fopen(const char* path, const char* mode)
{int flags = 0;if(strcmp(mode, "r") == 0){flags |= O_RDONLY;}else if(strcmp(mode, "w") == 0){flags |= (O_CREAT|O_WRONLY|O_TRUNC);}else if(strcmp(mode, "a") == 0){flags |= (O_CREAT|O_WRONLY|O_APPEND);}else{}int fd = 0;if(flags & O_RDONLY)fd = open(path, flags);else{fd = open(path, flags, 0666);}if(fd < 0){errno = 2;return NULL;}myFILE* fp = (myFILE*)malloc(sizeof(myFILE));if(fp == NULL){errno = 3;return NULL;}fp->_end = 0;fp->_fileno = fd;return fp;
}int my_fputs(const char* s, myFILE* stream)
{memcpy(stream->_buffer + stream->_end, s, strlen(s));stream->_end += strlen(s);if(stream->_buffer[stream->_end - 1] == '\n'){my_fflush(stream);}return strlen(s);
}int my_fflush(myFILE* stream)
{if(stream->_end > 0);write(stream->_fileno, stream->_buffer, stream->_end);stream->_end = 0;return 1;
}int my_fclose(myFILE* fp)
{my_fflush(fp);close(fp->_fileno);return fp->_fileno;
}
#include <unistd.h>
#include "mylib.h"int main()
{myFILE* fp = my_fopen("log.txt", "w");const char* str = "hello world\n";int i = 0;for(i = 0; i < 20; i++){ my_fputs(str, fp);sleep(1);}my_fclose(fp);return 0;
}

在这里插入图片描述

相关文章:

Linux——缓冲区

我在上篇博客留下了一个问题&#xff0c;那个问题就是关于缓冲区的问题&#xff0c;我们发现 文件有缓冲区&#xff0c;语言有用户级缓冲区&#xff0c;那么缓冲区到底是什么&#xff1f;&#xff0c;或者该怎 么认识缓冲区&#xff1f;这篇文章或许会让你有所认识&#xff0c;…...

Mac 生成Android签名证书 .keystore文件

工具下载地址 https://www.oracle.com/java/technologies/downloads/#jdk21-mac1. 找到安装jdk的路径&#xff0c;并进入bin目录下 1.1 查找JDK命令 /usr/libexec/java_home -v结果为: java_home: option requires an argument -- v /Library/Java/JavaVirtualMachines/jdk…...

电商数仓项目----笔记六(数仓ODS层)

ODS层的设计要点如下&#xff1a; &#xff08;1&#xff09;ODS层的表结构设计依托于从业务系统同步过来的数据结构。 &#xff08;2&#xff09;ODS层要保存全部历史数据&#xff0c;故其压缩格式应选择压缩比较高的&#xff0c;此处选择gzip。 &#xff08;3&#xff09;…...

rtsp视频在使用unity三维融合播放后的修正

1 rtsp 接入 我们使用unity UE 等三维渲染引擎中使用c编写插件来接入rtsp 视频。同时做融合的时候&#xff0c;和背景的三维颜色要一致&#xff0c;这就要使用视频融合修正技术。包括亮度&#xff0c;对比度&#xff0c;饱和度的修正。在单纯颜色上的修正可以简单使用rgb->…...

【已解决】解决Springboot项目访问本地图片等静态资源无法访问的问题

今天在开发一个招聘系统的时候&#xff0c;有投递简历功能&#xff0c;有投递就会有随之而来的查看简历对吧&#xff0c;我投递过的简历&#xff0c;另存为一个文件夹&#xff0c;就是说本地磁盘(或者服务器)有一个专门存放投递过的简历的文件夹&#xff0c;用于存放PDF&#x…...

运维笔记之centos部署Go-FastDfs

安装Go-FastDfs 当前最新版本为1.4.5&#xff0c;但发布的最新版本为1.4.4 # 下载文件 wget --no-check-certificate https://github.com/sjqzhang/go-fastdfs/releases/download/v1.4.4/fileserver -O fileserver # 赋权限 chmod x fileserver # 运行 ./fileserver server服…...

C#基础——线程(线程池、线程锁、线程抢占、多线程)

线程 进程&#xff08;Process&#xff09;是由操作系统分配资源并执行的一个独立的程序实&#xff0c;属于Windows的概念&#xff0c;进程结束就表示程序关闭了。 线程&#xff08;Thread&#xff09;是程序中执行的最小单位。一个线程代表了一个独立的执行流&#xff0c;可…...

C# WPF上位机开发(QT vs WPF)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 最近经常收到朋友们的私信&#xff0c;他们对C# WPF开发很感兴趣&#xff0c;但是呢&#xff0c;正当准备学习的时候&#xff0c;又有人告诉他们应…...

2-高可用-负载均衡、反向代理

负载均衡、反向代理 upstream server即上游服务器&#xff0c;指Nginx负载均衡到的处理业务的服务器&#xff0c;也可以称之为real server,即真实处理业务的服务器。 对于负载均衡我们要关心的几个方面如下&#xff1a; 上游服务器配置&#xff1a;使用upstream server配置上…...

STM32 使用ARM仿真器设置

STM32单片机程序下载到单片机芯片中有两种方式&#xff0c;①编译生成HEX&#xff0c;使用程序烧录软件刷到单片机芯片里。②使用ARM仿真器下载程序。使用ARM仿真器的优势是&#xff0c;在工程编译没问题直接在Keil软件里就可以将程序下载到单片机里&#xff0c;并且程序可以在…...

【Java】spring

一、spring spring是一个很大的生态圈&#xff0c;里面有很多技术。 其中最基础的是spring framework&#xff0c;主要的技术 是springboot以及springcloud。 1、spring framework spring framework是spring生态圈中最基础的项目&#xff0c;是其他项目的基础。 1.1、核心…...

C语言中关于操作符的理解

本篇文章只会列出大家在生活中经常使用的操作符 算术操作符 在算数操作符中常用的有&#xff0c;&#xff0c;-&#xff0c;*&#xff0c;/&#xff0c;% &#xff0c;我们重点讲一讲 / (除) 和 % (模) " / "运算 #include <stdio.h>int main() {int a5/2;fl…...

Flutter本地化(国际化)之App名称

文章目录 Android国际化IOS国际化 Flutter开发的App&#xff0c;如果名称想要跟随着系统的语言自动改变&#xff0c;则必须同时配置Android和IOS原生。 Android国际化 打开android\app\src\main\res\values 创建strings.xml 在values上右键&#xff0c;选择New>Values Res…...

Redis哨兵源码分析

在Redis server启动过程中&#xff0c;实现了实例化和初始化 1、哨兵实例化过程&#xff0c;采用redis sentinel指令实例化还是redis server下的参数实例化--sentinel。 // 检查服务器是否以 Sentinel 模式启动 server.sentinel_mode checkForSentinelMode(argc,argv);/* Re…...

安装Neo4j

jdk1.8对应的neo4j的版本是3.5 自行下载3.5版本的zip文件 地址 解压添加环境变量 变量名&#xff1a;NEO4J_HOME 变量值&#xff1a;D:\neo4j-community-3.5.0 &#xff08;你自己的地址&#xff09; PATH添加&#xff1a; %NEO4J_HOME%\bin (如果是挨着的注意前后英…...

华为鸿蒙开发适合哪些人学习?

随着鸿蒙系统的崛起&#xff0c;越来越多的人开始关注鸿蒙开发&#xff0c;并希望成为鸿蒙开发者。然而&#xff0c;鸿蒙开发并不适合所有人&#xff0c;那么哪些人最适合学习鸿蒙开发呢&#xff1f;本文将为您总结鸿蒙开发适合的人群。 一、具备编程基础的人 学习鸿蒙开发需要…...

深信服技术认证“SCSA-S”划重点:命令执行漏洞

为帮助大家更加系统化地学习网络安全知识&#xff0c;以及更高效地通过深信服安全服务认证工程师考核&#xff0c;深信服特别推出“SCSA-S认证备考秘笈”共十期内容&#xff0c;“考试重点”内容框架&#xff0c;帮助大家快速get重点知识~ 划重点来啦 *点击图片放大展示 深信服…...

Flink系列之:Savepoints

Flink系列之&#xff1a;Savepoints 一、Savepoints二、分配算子ID三、Savepoint 状态四、算子五、触发Savepoint六、Savepoint 格式七、触发 Savepoint八、使用 YARN 触发 Savepoint九、使用 Savepoint 停止作业十、从 Savepoint 恢复十一、跳过无法映射的状态恢复十二、Resto…...

使用宝塔面板部署前端项目到服务器

目录 文章目录 前言 一、第一步&#xff1a;创建文件夹 二、第二步&#xff1a;部署前端项目 三、第三步&#xff1a;打开防火墙 文章目录 前言第一步&#xff1a;创建文件夹第二步&#xff1a;部署前端项目第三步&#xff1a;打开防火墙总结 前言 在此之前&#xff0c;我…...

Enge问题解决教程

目录 解决问题的一般步骤&#xff1a; 针对"Enge问题"的具体建议&#xff1a; 以下是一些普遍适用的解决问题的方法&#xff1a; 以下是一些更深入的Enge浏览器问题和解决办法&#xff1a; 浏览器性能问题&#xff1a; 浏览器插件与网站冲突&#xff1a; 浏览…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

Python 包管理器 uv 介绍

Python 包管理器 uv 全面介绍 uv 是由 Astral&#xff08;热门工具 Ruff 的开发者&#xff09;推出的下一代高性能 Python 包管理器和构建工具&#xff0c;用 Rust 编写。它旨在解决传统工具&#xff08;如 pip、virtualenv、pip-tools&#xff09;的性能瓶颈&#xff0c;同时…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...