4. 标准 IO 库

news2024/11/28 16:45:32

4. 标准 IO 库

  • 1. 标准 IO 简介
  • 2. FILE 指针
  • 3. 标准输入、标准输出和标准错误
  • 4. fopen() 和 flose()
  • 5. fread() 和 fwrite()
  • 6. fseek 定位
  • 7. 检查或复位状态
    • 7.1 feof()
    • 7.2 ferrof()
    • 7.3 clearerr()
  • 8. 格式化 IO
    • 8.1 格式化输出
    • 8. 2 格式化输入
  • 9. IO 缓冲
    • 9.1 文件 IO 的内核缓冲
    • 9.2 刷新文件 IO 的内核缓冲区
      • 9.2.1 控制文件 IO 内核缓冲的系统调用
      • 9.2.1 控制文件 IO 内核缓冲的标志
    • 9.3 直接 IO,绕过内核缓冲
      • 9.3.1 直接 IO 的对齐限制
      • 9.3.2 直接 IO 与普通 IO 对比
    • 9.4 stdio 缓冲
      • 9.4.1 设置 stdio 缓冲
        • 9.4.1.1 setvbuf()
        • 9.4.1.2 setbuf()
        • 9.4.1.3 setbuffer()
      • 9.4.2 缓冲模式
      • 9.4.3 刷新 stdio 缓冲区
  • 10. 文件描述符和FILE指针互转

1. 标准 IO 简介

标准 IO 库指的式标准 C 库中用于文件 IO 操作相关的一系列库函数的集合,底层是用系统 IO 实现的。但是标准 IO 比系统 IO 具有更好的可移植性,因为不同的操作系统内核提供的系统调用都是不一样的;其次标准 IO 具有更高的效率,因为标准 IO 提供了自己的缓冲区,但是系统 IO 不具备缓冲区。

2. FILE 指针

FILE 指针就类似于系统 IO 的文件描述符,FILE 指针是一个结构体类型,包含了标准 IO 为管理文件所需要的所有信息,包括文件描述符、指向文件缓冲区的指针、缓冲区的长度,当前缓冲区中的字节数以及出错标志等。该类型定义在stdio.h

3. 标准输入、标准输出和标准错误

标准输入和标准输出通常指的就是键盘和显示器,标准错误也是通过显示器显示的。
通过标准输入设备与系统进行交互时,进程将从标准输入 (stdin) 文件中获取数据,将正常输出数据输出到标准输出 (stdout) 文件,将错误信息输出到标准错误 (stderr) 文件中。标准输出文件和标准错误文件都对应终端的屏幕,而标准输入文件则对应于键盘。

4. fopen() 和 flose()

#include <stdio.h>
int flose(FILE *stream);// 成功返回0,失败返回-1
FILE *fopen(const char *path, const cchar *mode);// 成功返回FILE文件指针,失败返回NULL
/* 参数:
 * path: 文件路径,可以是相对路径,也可以是绝对路径
 * mode: 文件权限,是一个字符串
 * r:只读
 * r+:可读可写
 * w:只写,如果文件存在,就将文件截断为0,否则就创建文件
 * w+:可读可写方式打开文件,如果存在就截断为0,否则就创建文件
 * a:只写,默认是追加式写入,如果文件不存在就创建文件
 * a+:可读可写,以追加的方式写入,如果文件不存在就创建文件
 * /
// 如果文件不存在就会创建文件,新文件的默认权限是0666

5. fread() 和 fwrite()

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);
/* 参数:
 * ptr:存放读取到的数据或者需要写入的数据的缓冲区
 * size:读取或写入的数据大小的单位,那么总共数据的大小是size*nmemb
 * nmemb:读取或写入的数据个数
 * stream:FILE指针
 */

6. fseek 定位

#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
// 这里的后两个参数和lseek相同,成功返回0,失败返回-1
long ftell(FILE *stream);
// 获取当前读写位置偏移量

7. 检查或复位状态

fread() 读取数据时,如果返回值小于 nmemb,表示发生了错误或者已经读到了文件末尾,但是不能具体确定是哪种情况,可以通过判断错误标志或 end-of-file 标志来确定具体情况

7.1 feof()

用于测试文件的 end-of-file 标志,如果被设置了,则调用 feof() 函数将返回一个非零值,如果没有被设置就返回0.

#include <stdio.h>
int feof(FILE *stream);
// 当文件的读写位置到结尾时,end-of-file 会被设置

7.2 ferrof()

用于测试文件的错误标志,如果错误标注被设置,返回非零值,否则返回 0.

#include <stdio.h>
int ferror(FILE *stream);

7.3 clearerr()

用于清除 end-of-file 或错误标志,当调用上面两个函数校验完之后,通常需要清除这些标志,避免下次校验时使用到的是上一次的值。对于 end-of-file,除了显示清除外,调用 fseek 会自动清除

#include <stdio.h>
void clearerr(FILE *stream);

8. 格式化 IO

8.1 格式化输出

#include <stdio.h>
int print(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,...);
// format:格式化控制字符串,用于指定后续的参数如何进行格式转换
fprintf(stderr,"hello world\n");
fprintf(stderr,"%d\n",5);

dprintf(STDERR_FILENO,"hello world\n");
dprintf(STDERR_FILENO,"%d\n",5);

char buf[100];
sprintf(buf,"hello world\n");
sprintf(buf,"%d",100);// 将整形转换为字符串,并且自动在末尾加上一个终止符

// 因为sprinf可能会发生缓冲区溢出,就引入了snprintf
// size规定了缓冲区的大小,如果写入到缓冲区的字节数大于size,超出的部分就会丢弃

format:%[flags][width][.precision][length]type
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8. 2 格式化输入

#include <stdio.h>
int scanf(const char *format,...);
int fscanf(FILE *stream, const char *format,...);
int sscanf(const char *str, const char *format,...);
int a,b,c;
scanf("%d%d%d", &a&b&c);
// 使用该函数时,进程会被阻塞,直到键盘有数据输入

int a2,b2,c2;
fscanf(stdin,"%d%d%d",&a2,&b2,&c2);

char *str="5454 hello";
char buf[10];
int a3;
sscanf(str, "%d%s",&a,buf);

format:%[*][width][ength]type%[m][width][ength]type
如果添加了 *,格式化输入函数会按照转换说明的指示读取输入,但是丢弃输入,意味着不需要对转换后的结果进行存储,所以也就不需要提供相应的指针参数。如果添加了 m,就只能与%s、 %c 以及%[一起使用,调用者无需分配相应的缓冲区来保存格式转换后的数据,原因在于添加了 m,这些格式化输入函数内部会自动分配足够大小的缓冲区,并将缓冲区的地址值通过与该格式转换相对应的指针参数返回出来,该指针参数应该是指向 char*变量的指针。随后,当不再需要此缓冲区时,调用者应调用 free() 函数来释放此缓冲区。

9. IO 缓冲

9.1 文件 IO 的内核缓冲

文件 IO 在进行文件读写操作时并不会直接访问磁盘设备,而是仅仅在用户空间缓冲区和内核缓冲区之间复制数据,也就是说系统调用和磁盘操作不是同步的。当多个线程同时向文件写入数据时,就会将文件存放在缓冲区中,然后只进行依次和磁盘的 IO 操作。

9.2 刷新文件 IO 的内核缓冲区

强制将文件 IO 的内核缓冲区中缓存的数据刷新到磁盘设备中

9.2.1 控制文件 IO 内核缓冲的系统调用

#include <unistd.h>
int fsync(int fd);
int fdatasync(int fd);
void sync(void);// 不是对某个指定的文件数据进行更新,而是刷新所有文件 IO 内核缓冲区

9.2.1 控制文件 IO 内核缓冲的标志

fd=open(filepath,O_WRONLY|O_DSYNC);		// 类似在每个write后调用fdatasync函数
fd=ofen(filepath,O_WRONLY|O_SYNC);		// 每个write都会自动将文件内容数据和元数据刷新

9.3 直接 IO,绕过内核缓冲

fd=open(filepath,O_WRONLY|O_DIRECT);

9.3.1 直接 IO 的对齐限制

  • 应用程序中用于存放数据的缓冲区,其内存起始地址必须以块大小的整数倍进行对齐
  • 写文件时,文件的位置偏移量必须是块大小的整数倍
  • 写入到文件的数据大小必须是块大小的整数倍
    确认块大小指令df -h查看 Ubuntu 系统的跟文件系统所挂载的磁盘分区,接着sudo tune2fs -l /dev/sda1 | grep "Block size"

9.3.2 直接 IO 与普通 IO 对比

直接 IO 每次都是直接对磁盘发起操作,而普通方式只是将用户空间下的数据拷贝到文件 IO 内核缓冲区中。直接 IO 效率、性能低,只有一些特殊场合用到

9.4 stdio 缓冲

标准 IO 效率比 文件 IO 高的根本就是它维护了自己的缓冲区,减少了和磁盘的交互

9.4.1 设置 stdio 缓冲

9.4.1.1 setvbuf()
#include <stdio.h>
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
// 如果 buf 不为 NULL,那么buf指向size大小的内存区域将作为该文件的stdio缓冲区,所以buf应该以动态分配或静态的方式在堆上开辟空间,而不是在栈上的函数内分配局部变量。如果buf为NULL,那么stdio库会自动分配一块空间作为该文件的stdio缓冲区,除非mode配置为非缓冲区模式
/* mode:指定缓冲区的缓冲类型
 * _IONBF:不对 IO 进行缓冲。每个标准IO函数将立即调用write或read,并且忽略buf和size参数,可以指定为NULL和0,stderr就是这类
 * _IOLBF:采用行缓冲,遇到换行符才会执行文件IO操作。对于输出流,在输出一个换行符前将数据缓存(除非缓冲区已经被填满), 当输出换行符时,再将这一行数据通过文件 I/O write()函数刷入到内核缓冲区中;对于输入流, 每次读取一行数据。 对于终端设备默认采用的就是行缓冲模式,譬如标准输入和标准输出。
 * _IOFBF: 采用全缓冲 I/O。 在这种情况下,在填满 stdio 缓冲区后才进行文件 I/O 操作(read、 write)。对于输出流,当 fwrite 写入文件的数据填满缓冲区时,才调用 write()将 stdio 缓冲区中的数据刷入内核缓冲区;对于输入流, 每次读取 stdio 缓冲区大小个字节数据。 默认普通磁盘上的常规文件默认常用这种缓冲模式
 */
// size指定缓冲区大小

当 stdio 缓冲区中的数据被刷入到内核缓冲区或被读取之后,这些数据就不会存在于缓冲区中了,数据被刷入了内核缓冲区或被读走了

9.4.1.2 setbuf()
#include <stdio.h>
void setbuf(FILE *stream, char *buf);

执行和 setvbuf 类似的任务

9.4.1.3 setbuffer()
#include <stdio.h>
void setbuffer(FILE *stream, char *buf, size_t size);

和setbuf类似,但是可以指定缓冲的大小

9.4.2 缓冲模式

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
	// setvbuf(stdout, NULL, _IONBF, 0);// 将stdout设置为无缓冲
	printf("Hello World!\n");
	printf("Hello World!");
	for ( ; ; )
		sleep(1);
}

上面的代码只能看到第一个打印信息,第二个看不到,因为第一个是行缓冲,而第二个是全缓冲,只有当程序结束会刷新缓冲区。如果去掉注释,那么两个都可以打印出来。

9.4.3 刷新 stdio 缓冲区

#include <stdio.h>
int fflush(FILE *stream);	// 刷新缓冲区
int fclose(FILE *stream);	// 关闭缓冲区

强制刷新缓冲区,如果 stream 为 NULL,就表示刷新所有 stdio 缓冲区。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
	printf("Hello World!\n");
	printf("Hello World!");
	fflush(stdout);
	// fclose(stdout);
	for ( ; ; )
		sleep(1);
}

上面代码一样可以看到两个打印信息。同样,关闭文件也可以刷新缓冲区

10. 文件描述符和FILE指针互转

有时需要将文件 IO 和标准 IO 混合使用

#include <stdio.h>
int fileno(FILE *stream);
FILE *fdopen(int fd, const char *mode);

当混合使用时,需要注意缓冲的问题,文件 IO 会直接将数据写入到内核缓冲区进行高速缓存,而标准 IO 会将数据写入到 stdio 缓冲区,之后再调用 write() 将 stdio 缓冲区中的数据写入到内核缓冲区。比如:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
	printf("print");
	write(STDOUT_FILENO,"write\n",6);
	exit(0);
}
// 这里先输出了write的内容,然后再输出print的内容,因为print没有遇到换行符,也就是清除缓冲区,只有等到运行结束之后才清理

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

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

相关文章

【古诗生成AI实战】之五——加载模型进行古诗生成

回顾上一篇博客&#xff0c;我们已经成功地训练了我们的模型&#xff0c;并将其保存下来。这是一个重要的里程碑&#xff0c;因为训练好的模型是我们进行文本生成的基础。 现在&#xff0c;接下来的步骤是加载这个训练好的模型&#xff0c;然后使用它来生成古诗。 本章的内容属…

AI4S Cup学习赛-中枢神经系统药物研发:药物筛选与优化

赛题介绍 链接&#xff1a;Bohrium 案例广场 (dp.tech) 中枢神经系统类疾病长期以来存在着重要的临床未满足需求。据统计&#xff0c;在当前人口老龄化趋势下&#xff0c;阿兹海默&#xff08;AD&#xff09;、帕金森病&#xff08;PD&#xff09;等神经退行性疾病和脑癌、中…

ATK-ESP8266 WIFI模块串口通信通用实现方案

ATK-ESP8266 WIFI模块是一种常用的无线模块&#xff0c;它可以通过串口与外部设备进行通信&#xff0c;实现数据的收发和控制。本文将介绍一种通用的实现方案&#xff0c;帮助您在项目中使用ATK-ESP8266 WIFI模块进行串口通信。 【方案概述】 这个通用实现方案涵盖了ATK-ESP82…

探索 Rollup:简化你的前端构建流程

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

SCI一区级 | Matlab实现GWO-CNN-LSTM-selfAttention多变量多步时间序列预测

SCI一区级 | Matlab实现GWO-CNN-LSTM-selfAttention多变量多步时间序列预测 目录 SCI一区级 | Matlab实现GWO-CNN-LSTM-selfAttention多变量多步时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现GWO-CNN-LSTM-selfAttention灰狼算法优化卷积长短…

Java8实战-总结49

Java8实战-总结49 CompletableFuture&#xff1a;组合式异步编程对多个异步任务进行流水线操作构造同步和异步操作将两个 CompletableFuture 对象整合起来&#xff0c;无论它们是否存在依赖 CompletableFuture&#xff1a;组合式异步编程 对多个异步任务进行流水线操作 构造同…

jdk17安装全方位手把手安装教程 / 已有jdk8了,安装JDK17后如何配置环境变量 / 多个不同版本的JDK,如何配置环境变量?

&#x1f9f8;欢迎来到dream_ready的博客&#xff0c;&#x1f4dc;相信您对博主首页也很感兴趣o (ˉ▽ˉ&#xff1b;) 学生邮箱白嫖/免费安装JetBrains全家桶(IDEA/pycharm等) —— 保姆级教程 目录 1、下载jdk17 2、安装jdk17 3、配置环境变量 -> 电脑无其他jdk 4、…

Windows安装Python环境(V3.6)

文章目录 一&#xff1a;进入网址&#xff1a;https://www.python.org/downloads/ 二&#xff1a;执行安装包 默认C盘&#xff0c;选择自定义安装目录 记得勾选add python path 下面文件夹最好不要有 . 等特殊符号 可以创建 python36 如果安装失败Option可以选默认的&#x…

IDEA DeBug

文章目录 01_Debug简介和意义02_IDEA中的Debug步骤03_跳转到当前代码执行的行04_步过调试的使用05_步入调试的使用06_强制步入调试的使用07_步出调试的使用08_回退断点调试的使用09_运行到光标处10_计算表达式11_条件断点12_多线程调试 01_Debug简介和意义 什么是程序DeBug&am…

PCIE链路训练-状态机描述4

Recovery Recovery.RcvrLock &#xff08;1&#xff09;如果link是在8.0GT/s或以上的速率工作&#xff0c;那么rx只会认为当前lane获得Block alignment之后收到的TS0&#xff0c;TS1&#xff0c;TS2是有效的。如果进入当前状态是从L1或recovery.speed或L0s&#xff0c;获取Blo…

STK Components 二次开发-地面站传感器

上一篇我们说了创建地面站&#xff0c;那么这次我们在地面站添加一些特效。 1. 创建地面站 var locationPoint1 new PointCartographic(m_earth, new Cartographic(Trig.DegreesToRadians(117.17066), Trig.DegreesToRadians(31.84056), 240.359)); m_facility new Platfor…

大型网站系统架构演化(Web)

大型网站系统架构演化 大型网站系统架构演化需要关注的维度涉及的技术演进过程单体架构垂直架构使用缓存改善网站性能缓存与数据库的数据一致性问题缓存技术对比Redis分布式存储方案Redis集群切片的常见方式Redis数据类型Redis 淘汰算法 大型网站系统架构演化 需要关注的维度 …

【虚拟机Ubuntu 18.04配置网络】

虚拟机Ubuntu 18.04配置网络 1.配置网络连接方式,查看自己网关 2.修改主机名 3.修改系统配置1.配置网络连接方式,查看自己网关 选择虚拟机镜像设置网络连接模式,可以选择桥接或者NAT连接(我这里选择是NAT连接) 确定自己网关&#xff0c;可以在虚拟机 -》 编辑 -》虚拟网络编…

Android 10.0 mtp模式下连接pc后显示的文件夹禁止删除copy重命名功能实现

1.前言 在10.0的系统开发中,usb连接pc端的时候有好几种模式,在做otg连接pc端的时候,改成mtp模式的时候,在pc端可以看到产品设备 的显示的文件夹的内容,对于产品设备里面的文件在pc端禁止做删除重命名拷贝等操作功能的实现 2.mtp模式下连接pc后显示的文件夹禁止删除copy重命…

微信小程序开发学习——小程序基本架构

1.创建一个包含&#xff1a;首页、咨询、关于我们 3个标签的小程序&#xff0c;每个标签都有对应的页面、图标和标签文字。 知识点&#xff1a;app.json文件对小程序进行全局配置&#xff0c;同名.json文件对本窗口进行配置 app.json属性&#xff1a; pages用于指定小程序由哪…

sql语句在字段中使用select

有两个表如下&#xff1b;产品表&#xff0c;产品评论表&#xff1b; 查询全部产品信息和每种产品的评论数量&#xff1b; 这也是子查询的一种&#xff1b; select * from product1; select * from comment; SELECT product1.*,(select count(id) from comment where product1…

docker打包前端镜像

文章目录 一、构建镜像二、查看本地镜像三、启动容器四、查看启动的容器五、保存镜像六、读取镜像七、创建镜像八、最后 docker官网 一、构建镜像 -t是给镜像命名&#xff0c;.(点)是基于当前目录的Dockerfile来构建镜像 docker build -t image_web .二、查看本地镜像 docke…

nodejs微信小程序+python+PHP-婚纱摄影预约系统的设计与实现-安卓-计算机毕业设计

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

Ubuntu:安装VSCode

参考博客Ubuntu下安装VSCODE_ubuntu安装vscode-CSDN博客中的第二种方式【安装包方式安装】&#xff0c;即可&#xff0c;安装非常easy~~~ 安装包方式安装&#xff1a; 1. 从VSCode官网下载最新版的deb安装包&#xff1a; https://code.visualstudio.com/Download&#xff0c;…

手把手教会你--github的学习--持续更新

有什么问题&#xff0c;请尽情问博主&#xff0c;QQ群796141573 前言1.1 使用过程(1) 进入某个项目(2) 点击某个文件(3) 在源码区域下面(4) 源码区的头顶上 1.2 作者的其他项目1.3 搜索1.4 复制别人的代码(即项目)到自己的空间内1.5 上传自己的Bugs(bushi1.6 在线修改文件1.7 评…