嵌入式Linux,标准I/O探究,函数相关详解。

标准 I/O 虽然是对文 件 I/O 进行了封装,但事实上并不仅仅只是如此,标准 I/O 会处理很多细节,譬如分配 stdio 缓冲区、以优化的块长度执行 I/O 等。

1.标准 I/O 库介绍

通常标准 I/O 库函数相关的函数定义都在头文件 <stdio.h> 中,所以我们需要在程序源码中包含 <stdio.h> 头文件。
标准 I/O 库函数是构建于文件 I/O open() read() write() lseek() close() 等)这些系统调用之上的, 譬如标准 I/O 库函数 fopen() 就利用系统调用 open() 来执行打开文件的操作、 fread() 利用系统调用 read() 来执行读文件操作、fwrite() 则利用系统调用 write() 来执行写文件操作等等。
设计库函数是为了提供比底层系统调用更为方便、好用的调用接口,虽然标 准 I/O 构建于文件 I/O 之上,但标准 I/O 却有它自己的优势,标准 I/O 和文件 I/O 的区别如下
        1.  虽然标准 I/O 和文件 I/O 都是 C 语言函数,但是标准 I/O 是标准 C 库函数,而文件 I/O 则是 Linux 系统调用;
        2.  标准 I/O 是由文件 I/O 封装而来,标准 I/O 内部实际上是调用文件 I/O 来完成实际操作的;
        3.  可移植性:标准 I/O 相比于文件 I/O 具有更好的可移植性,通常对于不同的操作系统,其内核向应 用层提供的系统调用往往都是不同,譬如系统调用的定义、功能、参数列表、返回值等往往都是不 一样的;而对于标准 I/O 来说,由于很多操作系统都实现了标准 I/O 库,标准 I/O 库在不同的操作 系统之间其接口定义几乎是一样的,所以标准 I/O 在不同操作系统之间相比于文件 I/O 具有更好的可移植性。
        4.  性能、效率:标准 I/O 库在用户空间维护了自己的 stdio 缓冲区,所以标准 I/O 是带有缓存的,而文件 I/O 在用户空间是不带有缓存的,所以在性能、效率上,标准 I/O 要优于文件 I/O
其实标准I/O就从操作得角度来说,我个人认为和C语言对文件操作的流程理解是一样的,如果感兴趣的朋友可以看我下面这篇,或许可以帮助理解:
C语言文件操作icon-default.png?t=O83Ahttps://blog.csdn.net/YYYYYYJJJJJYYYYY/article/details/143994163
下面就直接开始讲解相关的函数

2.fopen()函数

使用 open() 系统调用打开或创建文件,而在标准 I/O 中,我们将使用库函数 fopen()打开或创建文件, fopen() 函数原型如下:
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
函数参数和返回值解释如下:
path 参数 path 指向文件路径,可以是绝对路径、也可以是相对路径。
mode 参数 mode 指定了对该文件的读写权限,是一个字符串,稍后介绍。
返回值: 调用成功返回一个指向 FILE 类型对象的指针( FILE * ),该指针与打开或创建的文件相关联,后续的标准 I/O 操作将围绕 FILE 指针进行。如果失败则返回 NULL ,并设置 errno 以指示错误原因。
参数 mode 字符串类型,取值为如下:
r  :以只读方式打开文件。
r+ :以可读、可写方式打开文件。
w :以只写方式打开文件,如果参数 path 指定的文件 存在,将文件长度截断为 0 ;如果指定文件不存在 则创建该文件。
w+ :以可读、可写方式打开文件,如果参数 path 指定 的文件存在,将文件长度截断为 0 ;如果指定文件不存在则创建该文件。
a :以只写方式打开文件,打开以进行追加内容(在文件末尾写入),如果文件不存在则创建该文
件。
a+ :以可读、可写方式打开文件,以追加方式写入(在文件末尾写入),如果文件不存在则创建该文件。

3. fclose()函数

调用 fclose() 库函数可以关闭一个由 fopen() 打开的文件,其函数原型如下:
#include <stdio.h>
int fclose(FILE *stream);
参数 stream FILE 类型指针,调用成功返回 0 ;失败将返回 EOF (也就是 -1 ),并且会设置 errno 来指示错误原因。

4. 读文件和写文件

当使用 fopen() 库函数打开文件之后,接着我们便可以使用 fread()fwrite() 库函数对文件进行读、写操作了,函数原型如下:
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
库函数 fread() 用于读取文件数据,其参数和返回值含义如下:
ptr fread() 将读取到的数据存放在参数 ptr 指向的缓冲区中;
size fread() 从文件读取 nmemb 个数据项,每一个数据项的大小为 size 个字节,所以总共读取数据大小为 nmemb * size 个字节。
nmemb 参数 nmemb 指定了读取数据项的个数。
stream FILE 指针。
返回值: 调用成功时返回读取到的数据项的数目(数据项数目并不等于实际读取的字节数,除非参数 size 等于 1 );如果发生错误或到达文件末尾,则 fread() 返回的值将小于参数 nmemb ,那么到底发生了错误 还是到达了文件末尾,fread() 不能区分文件结尾和错误,究竟是哪一种情况,此时可以使用 ferror() feof() 函数来判断。
库函数 fwrite() 用于将数据写入到文件中,其参数和返回值含义如下:
ptr 将参数 ptr 指向的缓冲区中的数据写入到文件中。
size 参数 size 指定了每个数据项的字节大小,与 fread() 函数的 size 参数意义相同。
nmemb 参数 nmemb 指定了写入的数据项个数,与 fread() 函数的 nmemb 参数意义相同。
stream FILE 指针。
返回值: 调用成功时返回写入的数据项的数目(数据项数目并不等于实际写入的字节数,除非参数 size 等于 1 );如果发生错误,则 fwrite() 返回的值将小于参数 nmemb (或者等于 0 )。
由此可知,库函数 fread() fwrite() 中指定读取或写入数据大小的方式与系统调用 read() write() 不同, 前者通过 nmemb (数据项个数) *size (每个数据项的大小)的方式来指定数据大小,而后者则直接通过一个 size 参数指定数据大小。

5.fseek()函数

库函数 fseek() 的作用类似于之前所提到 的系统调用 lseek() ,用于设置文件读写位置偏移量, lseek() 用于文件 I/O ,而库函数 fseek() 则用于标准 I/O ,其函数原型如下:
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
函数参数和返回值含义如下:
stream FILE 指针。
offset lseek() 函数的 offset 参数意义相同。
whence lseek() 函数的 whence 参数意义相同。
返回值: 成功返回 0 ;发生错误将返回 -1 ,并且会设置 errno 以指示错误原因;与 lseek() 函数的返回值 意义不同,这里要注意!
调用库函数 fread() fwrite() 读写文件时,文件的读写位置偏移量会自动递增,使用 fseek() 可手动设置文件当前的读写位置偏移量。

6.feof()函数

库函数 feof() 用于测试参数 stream 所指文件的 end-of-file 标志,如果 end-of-file 标志被设置了,则调用feof()函数将返回一个非零值,如果 end-of-file 标志没有被设置,则返回 0。 其函数原型如下:
#include <stdio.h>
int feof(FILE *stream);

7.ferror()函数

库函数 ferror() 用于测试参数 stream 所指文件的错误标志,如果错误标志被设置了,则调用 ferror() 函数 将返回一个非零值,如果错误标志没有被设置,则返回 0 。其函数原型如下:
#include <stdio.h>
int ferror(FILE *stream);

8.clearerr()函数

库函数 clearerr() 用于清除 end-of-file 标志和错误标志,当调用 feof() ferror() 校验这些标志后,通常需 要清除这些标志,避免下次校验时使用到的是上一次设置的值,此时可以手动调clearerr() 函数清除标志。 clearerr()函数原型如下:
#include <stdio.h>
void clearerr(FILE *stream);

9.格式化输出

C 库函数提供了 5 个格式化输出函数,包括: printf()fprintf()dprintf()sprintf()snprintf() 其函数定义如下:
#include <stdio.h>
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int dprintf(int fd, const char *format, ...);
int sprintf(char *buf, const char *format, ...);
int snprintf(char *buf, size_t size, const char *format, ...);
printf()函数:函数调用成功返回打印输出的字符数;失败将返回一个负值!
fprintf()函数:fprintf() 可将格式化数据写入到由 FILE 指针指定的文件中。
dprintf() 函数 :dprintf()可将格式化数据写入到由文件描述符 fd 指定的文件中。
sprintf() 函数 :sprintf()函数将格式化数据存储在由参数 buf 所指定的缓冲区中。
snprintf() 函数 sprintf()函数可能会发生缓冲区溢出的问题,存在安全隐患,为了解决这个问题,引入了 snprintf() 函数; 在该函数中,使用参数 size 显式的指定缓冲区的大小,如果写入到缓冲区的字节数大于参数 size 指定的大小,超出的部分将会被丢弃!如果缓冲区空间足够大,snprintf() 函数就会返回写入到缓冲区的字符数,与sprintf()函数相同,也会在字符串末尾自动添加终止字符 '\0' 。若发生错误,snprintf() 将返回一个负值!

10.格式化输入

C 库函数提供了 3 个格式化输入函数,包括: scanf()fscanf()sscanf() ,其函数定义如下:
#include <stdio.h>
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
scanf() 函数:

直接用法举例吧:

int a, b, c;
scanf("%d %d %d", &a, &b, &c);
当程序中调用 scanf() 的时候,终端会被阻塞,等待用户输入数据,此时我们可以通过键盘输入一些字 符,譬如数字、字母或者其它字符,输入完成按回车即可!接着来 scanf() 函数就会对用户输入的数据进行格 式转换处理。 函数调用成功后,将返回成功匹配和分配的输入项的数量;如果较早匹配失败,则该数目可能小于所提供的数目,甚至为零。发生错误则返回负值。
fscanf() 函数:
int a, b, c;
fscanf(stdin, "%d %d %d", &a, &b, &c);
此时它的作用与 scanf() 就是相同的,因为标准输入文件的数据就是用户输入的数据,譬如通过键盘输 入的数据。 函数调用成功后,将返回成功匹配和分配的输入项的数量;如果较早匹配失败,则该数目可能小于所提供的数目,甚至为零。发生错误则返回负值。
sscanf() 函数:
sscanf() 将从参数 str 所指向的字符串缓冲区中读取数据,作为格式转换的输入数据,所以它也有两个固定参数,字符串 str 和格式控制字符串 format。
char *str = "5454 hello";
char buf[10];
int a;
sscanf(str, "%d %s", &a, buf);
函数调用成功后,将返回成功匹配和分配的输入项的数量;如果较早匹配失败,则该数目可能小于所提供的数目,甚至为零。发生错误则返回负值。

前面语法里面的format:

width 最大字符宽度;
l ength 长度修饰符,与格式化输出函数的 format 参数中的 length 字段意义相同。
type 指定输入数据的类型。
举个例子:
scanf("%4s", buf); //匹配字符串,字符串长度不超过 4 个字符

其实就是引号里面百分号%和类型之间的那些东西,相信大家学过C语言都或多或少都知道这些,不熟悉了查查相关资料即可。

关于缓冲区的函数操作后续再罗列出。
不断学习中,共勉!!!

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

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

相关文章

github使用SSH进行克隆仓库

SSH 密钥拉取git 查询密钥是否存在 s -al ~/.ssh这个文件夹下 known_hosts 就是存在的密钥文件 创建密钥文件 ssh-keygen -t rsa -b 4096 -C "testtt.com"-t rsa 是 rsa 算法加密 -b 是指定密钥的长度&#xff08;以位为单位&#xff09;。 -C 是用于给密钥添加注…

江铃集团新能源携四款车型亮相香港车展,国际化布局成果显著

12月5日&#xff0c;2024年香港国际汽车博览会&#xff08;香港车展&#xff09;盛大开幕&#xff0c;来自全球上百个品牌齐聚一堂&#xff0c;上演了一场汽车盛筵。江铃集团新能源作为自主品牌的代表车企之一&#xff0c;持续推进国际化布局&#xff0c;为了满足不同地区用户的…

使用Unity脚本模拟绳索、布料(碰撞)

效果演示&#xff1a; 脚本如下&#xff1a; using System.Collections; using System.Collections.Generic; using UnityEngine;namespace PhysicsLab {public class RopeSolver : MonoBehaviour {public Transform ParticlePrefab;public int Count 3;public int Space 1;…

大数据-242 离线数仓 - 电商核心交易 数据导入 全量数据导入方案 产品分类、商家店铺、地域组织

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇开始了&#xff01; 目前开始更新 MyBatis&#xff0c;一起深入浅出&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff0…

【NLP 5、深度学习的基本原理】

目录 一、梯度下降算法 1.引例 —— 找极小值问题 目标&#xff1a; 方法&#xff1a; 2.梯度 例&#xff1a; 3.求解目标 为什么损失函数越小越好 4.梯度下降法 代码实现 5.细节问题 6.梯度爆炸和梯度消失 梯度爆炸 梯度消失 7.过拟合和欠拟合 欠拟合&#xff08;Underfitting…

云计算对定制软件开发的影响

在当代数字世界中&#xff0c;云计算是改变许多行业&#xff08;包括定制软件开发&#xff09;的最伟大的革命性趋势之一。由于这些公司努力寻求更好、更多不同的方式来履行职责&#xff0c;因此云计算与传统的内部部署基础设施相比具有许多不可否认的优势。这种范式转变对定制…

智能交通(8)——腾讯开悟智能交通信号灯调度赛道

本文档用于记录参加腾讯开悟智能信号灯调度赛道的模型优化过程。官方提供了dqn和target_dqn算法&#xff0c;模型的优化在官方提供的代码基础上进行。最终排名是在榜单16&#xff0c;没能进入最后的决赛。 一.赛题介绍 赛题简介&#xff1a;在本地赛题中&#xff0c;参赛团队…

RK3568平台开发系列讲解(IIO篇)IIO缓冲区

🚀返回专栏总目录 文章目录 一、IIO缓冲区的sysfs接口二、IIO缓冲区设置沉淀、分享、成长,让自己和他人都能有所收获!😄 📢IIO缓冲区提供连续的数据捕获,一次可以同时读取多个数据通道。可通过dev/iio:device字符设备节点从用户空间访问缓冲区。在触发器处理程序中,用…

mybatis用pagehelper 然后用CountJSqlParser45,发现自己手写的mapper查询效率很慢

如题 效率慢疑惑 效率慢 分页查询,发现效率很慢,然后发现是比较复杂的sql,CountJSqlParser45它不会帮忙优化掉,就是select多少字段它count的时候也还是这么多字段 框架里的用法是这样的 所以去看了CountJSqlParser45里面的代码,发现如果有group之类的,它就不帮忙把count优化…

k8s,dameonset

Docker容器里应用的日志&#xff0c;默认会保存在宿主机的/var/lib/docker/containers/{{.容器ID}}/{{.容器ID}}-json.log文件里 nodeAffinity toleration DaemonSet可以继续版本回退&#xff0c; kubectl rollout status命令看到这个“滚动更新”的过程&#xff0c;可以查看…

macmini安装ubuntu网卡驱动BCM4360

安装成功效果如下 成功连接wifi 成功分配到IP 执行命令如下 1. sudo apt update 2. sudo apt install broadcom-sta-dkms 3. 重启电脑

OSCP - Proving Grounds - Fanatastic

主要知识点 CVE-2021-43798漏洞利用 具体步骤 执行nmap 扫描&#xff0c;22/3000/9090端口开放&#xff0c;应该是ssh,grafana 和Prometheus Nmap scan report for 192.168.52.181 Host is up (0.00081s latency). Not shown: 65532 closed tcp ports (reset) PORT STA…

24/12/5 算法笔记<强化学习> doubleDQN,duelingDQN

我们前面了解了DQN网络的一些知识&#xff0c;然而DQN还有一些改进的方法&#xff0c;比如doubleDQN和duelingDQN,我们先来将一下doubleDQN和DQN. 先来对比一下 单一网络 vs. 双重网络 DQN:是一个深度神经网络来估计每个动作的Q值 DDQN:使用两个独立的深度神经网络&#xf…

时长输入框、用时输入框

时长输入框、用时输入框 行内组件&#xff0c;用于设定 【时 分 秒】 时长&#xff0c;转存结果为 【毫秒】 <template><div class"time-inputs"><div classtime-input-div v-ifinput><input classtime-input type"number" v-mod…

java反射的基础应用

一、堆内存中的情况 &#xff08;一&#xff09;对象创建与变化 源对象&#xff08;UserBo&#xff09;和目标对象&#xff08;User&#xff09; 在执行UserBo sourceObj new UserBo(username, password);和User targetObj new User();时&#xff0c;分别在堆内存中创建了U…

Unity3D常见的设计模式(五)

系列文章目录 unity知识点 文章目录 系列文章目录&#x1f449;前言&#x1f449;一、桥接模式&#xff08;Bridge&#xff09;&#x1f449;二、适配器模式&#xff08;Adapter&#xff09;&#x1f449;三、 外观模式&#xff08;Facade&#xff09;&#x1f449;四、原型模…

车机端同步outlook日历

最近在开发一个车机上的日历助手&#xff0c;其中一个需求就是要实现手机端日历和车机端日历数据的同步。然而这种需求似乎没办法实现&#xff0c;毕竟手机日历是手机厂商自己带的系统应用&#xff0c;根本不能和车机端实现数据同步的。 那么只能去其他公共的平台寻求一些机会&…

群控系统服务端开发模式-应用开发-邮件工厂结构封装

首先在系统根目录下extend文件夹下创建邮件工厂文件夹并更名叫Mail。 一、邮件发送父类 在Mail目录下创建邮件发送父类并更名为MailSenderInterface.php&#xff0c;代码如下 <?php /*** 邮件发送父类* User: 龙哥三年风水* Date: 2024/12/5* Time: 14:22*/ namespace Ma…

React性能优化

三个可以优化的地方 避免过度多次渲染 组件会在以下情况下重新渲染 注意&#xff1a;例如组件组合的形式&#xff0c;<Test><Counter></Counter></Test>,即使Test发生了重新渲染&#xff0c;Counter也不会重新渲染。另外使用React这样的库或框架时&a…

操作系统学习

问题&#xff1a; 因为想用傲梅来给系统盘扩容&#xff0c;导致无法进入操作系统&#xff0c;报错如下&#xff1a; 无法加载应用程序或操作系统&#xff0c;原因是所需文件丢失或包含错误. 文件:Windowslsystem32lwinload.efi错误代码: 0xc000007b 你需要使用恢复工具。如果…