嵌入式Linux,标准I/O探究,I/O缓冲,以及函数讲解

news2025/1/11 4:18:26
出于速度和效率的考虑,系统 I/O 调用(即文件 I/O open read write 等)和标准 C 语言库 I/O 函数(即标准 I/O 函数)在操作磁盘文件时会对数据进行缓冲。

1. 文件 I/O 的内核缓冲

read() write() 系统调用在进行文件读写操作的时候并不会直接访问磁盘设备,而是仅仅在用户空间缓 冲区和内核缓冲区(kernel buffer cache )之间复制数据。
比如调用 write()后仅仅只是将这 5 个字节数据拷贝到了内核空间的缓冲区中,拷贝完成之后函数就返回了,在后面的某个时刻,内核会将其缓冲区中的数据写入(刷新)到磁盘设备中,所以由此可知,系统调用 write()与磁盘操作并不是同步的,write()函数并不会等待数据真正写入到磁盘之后再返回。如果在此期间,其它进程调用 read()函数读取该文件的这几个字节数据,那么内核将自动从缓冲区中读取这几个字节数据返回给应用程序。 这个内核缓冲区就称为文件 I/O 的内核缓冲。

2. 文件 I/O 的内核缓冲区刷新函数

Linux 中提供了一些系统调用可用于控制文件 I/O 内核缓冲,包括系统调用 sync()syncfs()fsync()以 及 fdatasync()

1. fsync()函数

系统调用 fsync() 将参数 fd 所指文件的内容数据和元数据写入磁盘,只有在对磁盘设备的写入操作完成 之后,fsync() 函数才会返回,其函数原型如下:
#include <unistd.h>
int fsync(int fd);
参数 fd 表示文件描述符,函数调用成功将返回 0 ,失败返回 -1 并设置 errno 以指示错误原因。

2. fdatasync()函数

系统调用 fdatasync() fsync() 类似,不同之处在于 fdatasync() 仅将参数 fd 所指文件的内容数据写入磁盘,并不包括文件的元数据;同样,只有在对磁盘设备的写入操作完成之后,fdatasync() 函数才会返回,其函数原型如下:
#include <unistd.h>
int fdatasync(int fd);

3. sync()函数

系统调用 sync() 会将所有文件 I/O 内核缓冲区中的文件内容数据和元数据全部更新到磁盘设备中,该函 数没有参数、也无返回值,意味着它不是对某一个指定的文件进行数据更新,而是刷新所有文件 I/O 内核缓冲区。其函数原型如下:
#include <unistd.h>
void sync(void);

此外,调用 open()函数时指定一些标志也可以影响到文件 I/O 内核缓冲,也就是比如 O_DSYNC 标志和O_SYNC标志。在调用open()函数时和其他表示的语法一致。

O_DSYNC 标志,其效果类似于在每个 write() 调用之后调用 fdatasync() 函数进行数据同步。
O_SYNC 标志,使得每个 write() 调用都会自动将文件内容数据和元数据刷新到磁盘设备中,其效果类似于在每个 write() 调用之后调用 fsync() 函数进行数据同步。

3. 直接 I/O

Linux 内核 2.4 版本开始, Linux 允许应用程序在执行文件 I/O 操作时绕过内核缓冲区,从用户空间直接将数据传递到文件或磁盘设备,把这种操作也称为直接 I/O direct I/O )或裸 I/O raw I/O )。
这种方式,用得比较少,直接 I/O 方式效率、性能比较低,绝大部分应用程序不会使用直接 I/O 方式对文件进行 I/O 操作,通常只在一些特殊的应用场合下才可能会使用,所以感兴趣的朋友可以专门去查阅这一部分的用法。

4. stdio 缓冲

文件 I/O 内核缓冲,是由内核维护的缓冲区,而标准 I/O 所维护的 stdio 缓冲是用户空间的缓冲区,当应用程序中通过标准 I/O 操作磁盘文件时,为了减少调用系统调用的次数,标准 I/O 函数会将用户写入或读取文件的数据缓存在 stdio 缓冲区,然后再一次性将 stdio 缓冲区中缓存的数据通过调用系统调用 I/O (文件 I/O )写入到文件 I/O 内核缓冲区或者拷贝到应用程序的 buf 中。
C 语言提供了一些库函数可用于对标准 I/O stdio 缓冲区进行相关的一些设置,包括 setbuf()setbuffer()以及 setvbuf()

1. setvbuf()函数

调用 setvbuf() 库函数可以对文件的 stdio 缓冲区进行设置,譬如缓冲区的缓冲模式、缓冲区的大小、起始地址等。其函数原型如下:
#include <stdio.h>
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
函数参数和返回值解释如下:
stream FILE 指针,用于指定对应的文件,每一个文件都可以设置它对应的 stdio 缓冲区。
buf 如果参数 buf 不为 NULL ,那么 buf 指向 size 大小的内存区域将作为该文件的 stdio 缓冲区,因为stdio 库会使用 buf 指向的缓冲区,所以应该以动态(分配在堆内存,譬如 malloc )或静态的方式在堆中为该缓冲区分配一块空间,而不是分配在栈上的函数内的自动变量(局部变量)。如果 buf 等于 NULL ,那么 stdio 库会自动分配一块空间作为该文件的 stdio 缓冲区(除非参数 mode 配置为非缓冲模式)。
mode 参数 mode 用于指定缓冲区的缓冲类型,可取值如下:
  _IONBF 不对 I/O 进行缓冲(无缓冲)。意味着每个标准 I/O 函数将立即调用 write() 或者 read() ,并且忽略 buf size 参数,可以分别指定两个参数为 NULL 0 。标准错误 stderr 默认属于这一种类型,从而保证错误信息能够立即输出。
    _IOLBF 采用行缓冲 I/O 。在这种情况下,当在输入或输出中遇到换行符 "\n" 时,标准 I/O 才会执行文件 I/O 操作。对于输出流,在输出一个换行符前将数据缓存(除非缓冲区已经被填满),当输出换行符时,再将这一行数据通过文件 I/O write() 函数刷入到内核缓冲区中;对于输入流,每次读取一行数据。对于终端设备默认采用的就是行缓冲模式,譬如标准输入和标准输出。
    _IOFBF 采用全缓冲 I/O 。在这种情况下,在填满 stdio 缓冲区后才进行文件 I/O 操作( read write )。 对于输出流,当 fwrite 写入文件的数据填满缓冲区时,才调用 write() stdio 缓冲区中的数据刷入内核缓冲区;对于输入流,每次读取 stdio 缓冲区大小个字节数据。默认普通磁盘上的常规文件默认常用这种缓冲模式。
size 指定缓冲区的大小。
返回值: 成功返回 0 ,失败将返回一个非 0 值,并且会设置 errno 来指示错误原因。
注意,当 stdio 缓冲区中的数据被刷入到内核缓冲区或被读取之后,这些数据就不会存在于缓
冲区中了,数据被刷入了内核缓冲区或被读走了。

2. setbuf()函数

setbuf() 函数构建与 setvbuf() 之上,执行类似的任务,其函数原型如下:
#include <stdio.h>
void setbuf(FILE *stream, char *buf);

3. setbuffer()函数

setbuffer() 函数类似于 setbuf() ,但允许调用者指定 buf 缓冲区的大小,其函数原型如下:
#include <stdio.h>
void setbuffer(FILE *stream, char *buf, size_t size);

4. fflush()函数

无论我们采取何种缓冲模式,在任何时候都可以使用库函数 fflush() 来强制刷新(将输出到 stdio 缓冲区中的数据写入到内核缓冲区,通过 write() 函数) stdio 缓冲区,该函数会刷新指定文件的 stdio 输出缓冲区,此函数原型如下:
#include <stdio.h>
int fflush(FILE *stream);
参数 stream 指定需要进行强制刷新的文件,如果该参数设置为 NULL ,则表示刷新所有的 stdio 缓冲区。函数调用成功返回 0 ,否则将返回 -1 ,并设置 errno 以指示错误原因。
在一些其它的情况下,也会自动刷新 stdio 缓冲区,譬如当文件关闭时、程序退出时。
不断学习中,共勉!!!

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

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

相关文章

从单体到微服务:如何借助 Spring Cloud 实现架构转型

一、Spring Cloud简介 Spring Cloud 是一套基于 Spring 框架的微服务架构解决方案&#xff0c;它提供了一系列的工具和组件&#xff0c;帮助开发者快速构建分布式系统&#xff0c;尤其是微服务架构。 Spring Cloud 提供了诸如服务发现、配置管理、负载均衡、断路器、消息总线…

服务器数据恢复—LINUX下各文件系统删除/格式化的数据恢复可行性分析

Linux操作系统是世界上流行的操作系统之一&#xff0c;被广泛用于服务器、个人电脑、移动设备和嵌入式系统。Linux系统下数据被误删除或者误格式化的问题非常普遍。下面北亚企安数据恢复工程师简单聊一下基于linux的文件系统&#xff08;EXT2/EXT3/EXT4/Reiserfs/Xfs&#xff0…

<future> 注释3:conditional_t<T...>,void_t<T> 用于构成特化模板,

&#xff08;14&#xff09; 模板 conditional_t<T…> &#xff0c;定义于 < xtr1common > &#xff0c; 在本 模板里也会用到&#xff1a; &#xff08;15&#xff09;void_t 用于构成特化模板&#xff0c;只要 T 可以被编译器推断为某种类型&#xff0c;void_t 就…

一文速读:高速信号的完整性测试

随着人工智能的飞速发展&#xff0c;云计算的大量应用&#xff0c;汽车的电动、网联、智能化等催生高速互连器件行业技术变革和市场巨量增长。 从形态上来讲高速互连器件包括:高速线缆&#xff0c;连接器&#xff0c;高速背板和其他带高速接口的 PCB 板。从信号特征上来讲&…

Neo4j (desktop) 使用记录

1. neo4j community 使用 第一次使用Neo4j&#xff0c;根据网上的教程安装并配置了community版本&#xff0c; 在终端使用 neo4j.bat console 可以正常打开网页端 但是&#xff0c; 使用 neo4j start , neo4j stop 时会提示 ‘neo4j’ 时非法指令&#xff0c;无法识别 查明原…

关于信号隔离转换器

isolate converter是隔离转换器‌。它是一种在电子电路中用于实现电路隔离、电压转换或信号隔离的设备‌。隔离转换器能在很多场合发挥关键作用&#xff0c;比如可以保护电路、提高安全性&#xff0c;还能帮助不同电压或信号之间的转换与传递‌。 ‌一、产品概述‌ ‌简介‌&a…

如何通过自学成长为一名后端开发工程师?

大家好&#xff0c;我是袁庭新。最近&#xff0c;有星友向我提出了一个很好的问题&#xff1a;如何通过自学成为一名后端开发工程师&#xff1f; 为了解答这个疑问&#xff0c;我特意制作了一个视频来详细分享我的看法和建议。 戳链接&#xff1a;如何通过自学成长为一名后端开…

基于“微店 Park”模式下 2+1 链动模式商城小程序的创新发展与应用研究

摘要&#xff1a;本文以“微店 Park”从“开店工具”向“众创平台”的转型为背景&#xff0c;深入探讨 21 链动模式商城小程序在该平台情境下的应用潜力与创新发展路径。通过剖析“微店 Park”的运营模式&#xff0c;包括灵活承租、低成本入驻、多元流量引流等特点&#xff0c;…

[代码随想录09]字符串2的总结

前言 处理字符串主要是有思路&#xff0c;同时总结方法。 题目链接 151. 反转字符串中的单词 - 力扣&#xff08;LeetCode&#xff09; 55. 右旋字符串&#xff08;第八期模拟笔试&#xff09; 一、翻转字符串里的单词 这个题目的主要思路&#xff0c;代码采用从后往前遍历字…

海外的bug-hunters,不一样的403bypass

一种绕过403的新技术&#xff0c;跟大家分享一下。研究HTTP协议已经有一段时间了。发现HTTP协议的1.0版本可以绕过403。于是开始对lyncdiscover.microsoft.com域做FUZZ并且发现了几个403Forbidden的文件。 &#xff08;访问fsip.svc为403&#xff09; 在经过尝试后&#xff0…

【STM32 Modbus编程】-作为主设备读取保持/输入寄存器

作为主设备读取保持/输入寄存器 文章目录 作为主设备读取保持/输入寄存器1、硬件准备与连接1.1 RS485模块介绍1.2 硬件配置与接线1.3 软件准备2、读保持寄存器2.1 主设备发送请求2.2 从设备响应请求2.3 主机接收数据3、读输入寄存器4、结果4.1 保持寄存器4.2 输入寄存器在前面的…

数字图像处理 实验三 数字图像的几何运算

一、实验目的 掌握图像的基本几何变换的方法 1. 图像的平移 2. 图像的旋转 二、实验环境 1. PC计算机 2. MatLab软件/语言包括图像处理工具箱(Image Processing Toolbox) 3. 实验所需要的图片 三、实验原理 提示&#xff1a;图片平移就是实现运算 四、实验图像 图片名称&a…

卷积神经网络比于全连接神经网络强在哪?

卷积神经网络&#xff08;Convolutional Neural Networks&#xff0c;简称CNN&#xff09;与全连接神经网络&#xff08;Fully Connected Neural Networks&#xff0c;简称FFNN&#xff09;是深度学习和神经网络领域中两种最为常见的网络结构。两者在结构、工作原理及应用场景上…

超融合承载 PostgreSQL 数据库和 AI 系统的性能评测|金融行业实践

随着人工智能技术的日渐成熟&#xff0c;不少金融用户也开发了自己的 AI 应用系统&#xff0c;协助实际业务中诸如文字识别、图像转换、信息录入等工作&#xff0c;提升业务效率。不过&#xff0c;AI 应用系统普遍依赖 GPU 提供强大算力&#xff0c;对底层存储的性能也有较高的…

VBA信息获取与处理第四个专题第二节:将工作表数据写入VBA数组

《VBA信息获取与处理》教程(版权10178984)是我推出第六套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。这部教程给大家讲解的内容有&#xff1a;跨应用程序信息获得、随机信息的利用、电子邮件的发送、VBA互…

汽车IVI中控开发入门及进阶(三十七):基于HFP协议的蓝牙电话

概述: HFP全称Hands-free Profile,是一款让蓝牙设备控制电话的软件,多用于汽车上。此类设备最常见的例子是车载免提装置与蜂窝电话或可穿戴无线耳机一起使用。该配置文件定义了支持免提配置文件的两个设备如何在点对点的基础上相互交互。免提模式的实现通常使耳机或嵌入式免…

声音克隆技术:探索与实践 —— 从GPT-SoVITS V2到未来趋势20241201

声音克隆技术&#xff1a;探索与实践 —— 从GPT-SoVITS V2到未来趋势 引言&#xff1a;AI与声音创作的完美碰撞 &#x1f3a4;✨ 声音克隆技术正以惊人的速度改变语音生成的方式。从文本到语音&#xff0c;从音色到情感&#xff0c;人工智能赋予了声音创作全新的可能性。 在这…

ip地址显示本地局域网什么意思?ip地址冲突怎么解决

在日常使用网络的过程中&#xff0c;我们可能会遇到IP地址显示“本地局域网”的情况&#xff0c;同时&#xff0c;局域网内IP地址冲突也是一个常见且令人头疼的问题。本文将首先解释IP地址显示本地局域网的含义&#xff0c;随后详细探讨局域网IP地址冲突的解决方法&#xff0c;…

MR30分布式IO模块赋能喷水织机

纺织行业作为我国传统支柱产业&#xff0c;历经数千年的演变&#xff0c;如今仍面临着诸多困境&#xff0c;在纺织行业中&#xff0c;每一次技术的飞跃都是对行业边界的勇敢探索。在纺织行业&#xff0c;喷水织机作为关键生产设备&#xff0c;其性能直接影响到产品质量和产能。…

自建服务器,数据安全有保障

在远程桌面工具的选择上&#xff0c;向日葵和TeamViewer功能强大&#xff0c;但都存在收费昂贵、依赖第三方服务器、数据隐私难以完全掌控等问题。相比之下&#xff0c;RustDesk 凭借开源免费、自建服务的特性脱颖而出&#xff01;用户可以在自己的服务器上部署RustDesk服务端&…