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

Linux应用 标准I/O

标准I/O库

标准I/O库的函数都定义在**头文件<stdio.h>**中,其是建立在文件I/O(open(),close(),write(),read())这些系统调用之上的。

设置标准I/O库的目的是提供比底层系统调用更方便、好用的调用接口。同时标准I/O有更好的移植性。

标准I/O在用户空间维护了自己的stdio缓冲区,所以标准I/O是带缓存的,所以性能和效率上高于文件I/O。

FILE指针

前面说的文件I/O对于文件的操作是基于fd文件描述符的,在标准I/O中,对于文件的操作是基于FILE*进行的。

FILE 是一个结构体数据类型,其包含了标准I/O库函数为管理文件所需要的所有信息。包括文件描述符、指向文件缓冲区的指针、缓冲区的长度等等。

标准输入、输出、错误

标准输入:通常指计算机连接的键盘

标注输出:用于输出标准信息的设备、如显示器

标准错误:用来显示错误信息的设备、也是指显示器

整个流程:

用户通过标准输入设备与系统进行交互,进程将从标准输入(stdin)文件(把握重点)中得到输入数据,将正常输出数据(譬如程序中 printf 打印输出的字符串)输出到标准输出(stdout)文件,而将错误信息(譬如函数调用报错打印的信息)输出到标准错误(stderr)文件

进程所操作的输入、输出、错误都是基于文件产生的。标准输入对应键盘,标准输出和错误对应显示屏

每个进程默认都会打开这三个文件,得到0(in)、1(out)、2(error)文件标识符,这也就是我们的文件标识符为什么是以3开始的。

上面说的是文件I/O,在标准I/O中也存在宏定义

/* Standard streams. */
extern struct _IO_FILE *stdin;  /* Standard input stream. */
extern struct _IO_FILE *stdout;  /* Standard output stream. */
extern struct _IO_FILE *stderr;  /* Standard error output stream. */  
//_IO_FILE就是FILE结构体,它被typedef重命名了
/* C89/C99 say they're macros. Make them happy. */
#define stdin stdin
#define stdout stdout
#define stderr stderr

标准I/O函数

fopen()

对应文件I/O的open

#include <stdio.h>FILE* fopen(const char* path,const char* mode);  
//path指向路径
//mode指定读写权限
//失败了返回NULL
mode的种类

1、r 只读打开文件 , r+ :可读可写打开文件

2、w只写打开, w+:可读可写打开文件 w和w+打开文件时,如果文件存在就将文件截断为0,然后打开,如果不存在就创建一个指定路径的文件,然后再打开。

3、a:只写打开文件,a+:可读可写打开文件 ,a不仅仅在文件不存在的时候对文件进行创建,同时打开以后在文件末尾追加内容。

新建文件的权限

fopen函数中,没有要求我们传入新文件的权限,但是它有一个默认值,那就是

S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666) 文件拥有者、文件同组人、其他,他们的权限都是可读可写不可执行0x666

fclose()

传入结构体指针即可

#include <stdio.h>
int fclose(FILE *stream);
//关闭文件 回收FILE* 资源

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);//ptr:读或者写的缓冲区
//size:读或者写的数据大小
//nmemb:读或者写的数据个数
//调用成功以后会返回实际读或者写的数据个数。失败的话便返回-1
//可以使用ferror()来判断读写过程中发生了什么样的错误。

fseek定位

之前说的系统调用中出现了lssek()用来移动文件的读写指针,那么在标准I/O库中,也有对应的设置文件读写位置偏移量的函数,

#include <stdio.h>
int fseek(FILE* stream,long offset,int whence)
//stream: FILE结构体指针
//offset: 相对于whence的偏移量
//whence:文件的位置标识
//同lseek()函数相同,whence可取
//1、SEEK_SET:文件开头 2、SEEK_END:文件结尾 

ftell()

ftell()被用来获取文件当前的读写位置偏移量

#include <stdio.h>
long ftell(FILE *stream);
//调用失败返回-1
//单位是字节

错误检查

feof() 检查end-of-line标志

当使用fread()读文件的时候,如果我们要读的数据比文件本身的数据量大,我们使用fread()无法判断是读出错还是到达文件末尾,这时候我们需要通过查看文件的 end-of-file标志来判断是那种情况。feof()函数就可以检查文件的end-of-file标志

#include <stdio.h>int feof(FILE* stream); 
//如果end_of_file标志被设置了,就会返回一个非零值
//如果没有被设置就会返回0

ferror()函数 检查是否出现错误标志

这个函数用来测试指定文件的错误标标志,使用方法同feof()相同,如果有错误,就返回一个非零值,如果没有错误,就返回0;

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

clearerr()函数 清除end-of-line标志和错误标志

用来清除指定文件的end_of_file标志或者是错误标识,通常使用在检查完错误以后

#include <stdio.h>
void clearerr(FILE *stream);
//只要调用了就会清除
//调用fseek()成功以后也会清楚end_of_file标志 

格式化I/O

操作格式化控制字符串、可以以调用者指定的格式进行转换输出。

格式化输出

#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()和dprintf()写到指定的文件 sprintf()和snprintf()将格式化数据写到执行的缓冲区**(要确保缓冲区足够大)**

格式化输入

scanf()函数将用户输入(标准输入)的数据进行格式化转换并进行存储,它从格式化控制字符串format 参数的最左端开始,每遇到一个转换说明便将其与下一个输入数据进行“匹配”,如果二者匹配则继续,否则结束对后面输入的处理。

同上面一样、将printf换成scanf,同样有指定文件读取,指定缓冲区读取。

I/O缓冲

内核缓冲是对于硬盘来说的缓冲,stdio缓冲是对于内核缓冲来说的缓冲

文件 I/O 会直接将数据写入到内核缓冲区进行高速缓存,而标准 I/O 则会将数据写入到 stdio 缓冲区,之后再调用 write()将 stdio 缓冲区中的数据写入到内核缓冲区。

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

这样减少了内核访问磁盘的次数,提高了运行效率。

系统调用的缓冲刷新函数

系统调用的缓冲刷新指的是将内存缓冲区的数据写回磁盘,这样可以减少对磁盘的访问次数,提高运算的效率

fsync()函数
#include <unistd.h>
int fsync(int fd);
//将参数fd所指的文件内容和元数据写回磁盘。
//元数据包括文件大小、时间戳、权限等信息
fdatasync()函数
#include <unistd.h>
int fdatasync(int fd);
//仅仅将fd所指文件内容写入磁盘,不包括文件的元数据
sync()函数
#include <unistd.h>
void sync(void);
//刷新所有文件I/O内核缓冲区
ODSYNC标志 自动刷新(不包括元数据)

open时加上这个表示每个 write()调用之后调用 fdatasync()函数进行数据同步

O_SYNC标志 自动刷新 (包括元数据)

每个 write()调用都会自动将文件内容数据和元数据刷新到磁盘设备中

直接I/O、 不使用内核缓冲

Linux 允许应用程序在执行文件 I/O 操作时绕过内核缓冲区,从用户空间直接将数据传递到文件或磁盘设备,把这种操作也称为直接 I/O(direct I/O)或裸 I/O(raw I/O)

直接 I/O 只在一些特定的需求场合

在打开文件时加上O_DIRECT标志。

直接I/O的对齐限制

直接I/O是以数据块为单位的。

应用程序中用于存放数据的缓冲区,其内存起始地址必须以块大小的整数倍进行对齐;

写文件时,文件的位置偏移量必须是块大小的整数倍;

写入到文件的数据大小必须是块大小的整数倍。

在这里插入图片描述

直接 I/O 方式每次 write()调用均是直接对磁盘发起了写操作,而普通方式只是将用户空间下的数据拷贝到了文件 I/O 内核缓冲区中,并没直接操作硬件,所以消耗的时间短,硬件操作占用的时间远比内存复制占用的时间大得多直接 I/O 方式效率、性能比较低,绝大部分应用程序不会使用直接 I/O 方式对文件进行 I/O 操作,通常只在一些特殊的应用场合下才可能会使用,那我们可以使用直接 I/O 方式来测试磁盘设备的读写速率,这种测试方式相比普通 I/O 方式就会更加准确。

stdio缓冲

前面的内核缓冲是由内核维护的缓冲,stdio缓冲是用户维护的缓冲使用stdio缓冲可以减少系统调用的次数,进而提升效率。

标准 I/O 函数会将用户写入或读取文件的数据缓存在 stdio 缓冲区(使用缓冲区是标准I/O读写函数自动执行的),然后再一次性将 stdio 缓 冲区中缓存的数据通过调用系统调用 I/O(文件 I/O)写入到文件 I/O 内核缓冲区或者拷贝到应用程序的 buf 中

stdio缓冲相当于是系统缓冲的缓冲。

设置stdio缓冲
#include <stdio.h>
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
//mode:_IONBF:不缓冲	   _IOLB0F:行缓冲   _IOFBF:全缓冲(写满再缓冲)
void setbuf(FILE *stream, char *buf); //等价于setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ); 
//BUFSIZ 定义于头文件<stdio.h>中,该值通常为 8192void setbuffer(FILE *stream, char *buf, size_t size);  //同setbuf 但可以指定缓冲区大小 
// 等价于setvbuf(stream, buf, buf ? _IOFBF : _IONBF, size);

刷新缓冲区

#include <stdio.h>
int fflush(FILE *stream);   //将当前文件的stdio缓冲区数据写入内核缓冲区。  如果stream == NULL 表示刷新所有的stdio缓冲区

关闭文件后也会刷新缓冲区 fclose()关闭文件

程序退出以后也会刷新缓冲区

在这里插入图片描述

FILE*和fd的转换

#include <stdio.h>
int fileno(FILE *stream);
FILE *fdopen(int fd, const char *mode);
http://www.dtcms.com/a/439541.html

相关文章:

  • 【DeploySharp 】基于DeploySharp 的深度学习模型部署测试平台:安装和使用流程
  • 十一、Maven web项目的构建
  • 网站建设首选网站统计访客数量怎么做
  • 广东微信网站制作报价安装wordpress 脚本
  • 福州做企业网站百度权重1
  • 做论坛网站需要什么备案网页制作需要下载什么软件
  • 手机电影网站源码模板网站建设 中
  • 山东住房城乡建设厅网站首页wordpress主题新闻
  • 数据科学与AI的未来就业前景如何?
  • 网站怎么申请微博登录wordpress返佣
  • 企业网站建设参考资料中国建设银行网站登陆
  • 自己做网站主机jsp网站开发框架
  • 专业网站推广服务咨询网站建站描述撰写
  • [光学原理与应用-475]:不同制程的需要检测的缺陷的尺寸
  • 正则化方法:L1和L2正则化在神经网络中的应用(代码实现)
  • 做众筹网站有哪些平面设计视频
  • Redis分布式锁:从“能用就行”到“稳如老狗”的迭代方案
  • 国庆Day3
  • 棋牌类网站开发聚名网官网入口
  • Spring Boot 与数据访问全解析:MyBatis、Thymeleaf、拦截器实战
  • 永久免费个人网站申请注册电子购物网站开发公司
  • 工信部网站黑名单软件开发工程师的岗位职责
  • 阿里云做的网站为啥没有ftp汉南做网站
  • 深度学习是如何收敛的?梯度下降算法原理详解
  • 1.Kali Linux操作系统的下载(2025年10月2日)
  • JVM(七)--- 垃圾回收
  • 专门制作网站郑州男科医院哪家治疗比较好
  • 网站开发 需求文档结构设计网站推荐
  • 自定义异常类中的super(msg)的作用
  • 我想卖自己做的鞋子 上哪个网站好扬州市建筑信息平台