常用标准io
常用标准io
标准io基本概念
为满足用户访问文件的需求,提高用户程序的可移植性,标准库也提供了一组操作文件的函数接口,通常被称为标准io,标准io遵循ANSI C标准设计而来,目的是方便用户在不同操作系统下可以调用通用函数来实现对文件的读写访问,实际上,标准io是基于系统io设计出来的。
标准io基本API
一般情况区,关闭文件即可将标准缓冲区数据冲洗到内核缓冲区,当数据到内核缓冲区,数据则会写入到文件。
打开文件 fopen
头文件
#include <stdio.h>
函数原型
FILE *fopen(const char *path,const char *mode );
成功返回文件指针,失败返回NULL
功能:获取指定文件的文件指针
path:即将打开的文件
mode :
r | 只读方式打开文件,要求文件必须存在 |
---|---|
r+ | 读写方式打开文件,要求文件必须存在 |
w | 只读方式打开文件,文件不存在会新建文件,文件存在会清空文件 |
w+ | 读写方式打开文件,文件不存在会新建文件,文件存在会清空文件 |
a | 只写方式打开文件,文件不存在会创建文件,文件位置偏移量会自动定位到文件末尾(追加方式写数据) |
a+ | 读写方式打开文件,文件不存在会创建文件,文件位置偏移量会自动定位到文件末尾(追加方式写数据) |
标准io的都光标和写光标是不同的,且可以指向不同的位置。
FILE类型的指针
FILE类型其实是一个结构体数据类型,它包含了标准 I/O 库函数为管理文件所需要的所有信息,比如包括用于实际I/O 的文件描述符、指向文件缓冲区的指针、缓冲区的长度、当前缓冲区中的字节数以及出错标志等。
阅读stdio.h中的条件编译选项可以发现在stdio.h中还包含了另一个头文件<libio.h>,这个头文件中才有关于FILE结构体类型的定义
打开头文件<libio.h>之后,可以找到关于FILE结构体类型的定义,可以发现FILE结构体类型中的成员数量很多
以看到FILE结构体类型中有一个成员是FILE类型的指针变量chain,该指针可以指向下一个被打开文件的文件信息区,也就是可以把FILE类型当做数据结构中的链表的结点,结点中除了可以存储数据域之外,还可以利用指针域存储下一个结点的地址。
用户可以在一个程序中利用fopen函数打开多个文件,每次打开一个文件,内核就会从*堆内存*中申请一块FILE结构体大小的空间用来存储文件的所有信息,然后按照文件打开的顺序把每个打开的文件的结构体形成一条链表,然后使用链表头进行管理。
打开文件的目的无非就是对文件进行读写操作,所以每次当程序运行的时候已经有三个文件流被打开,分别是标准输入stdin、标准输出stdout、标准出错stderr,这三者在stdio.h中也是FILE指针。
关闭文件fclose
头文件
#include <stdio.h>
函数原型
int fclose (FILE *fp);
成功返回 0,失败返回EOF;
EOF是文件结束标志,是一个宏定义,值为-1;
功能:关闭指定文件并释放资源
fp:即将关闭的文件
关闭文件时,内核会将文件对应的堆内存从链表中删除,再释放。
使用标准IO的时候,是不可以反复关闭相同的文件,因为释放已经被释放的堆内存,会导致段错误
读取文件数据
用户打开文件后可以从文件中读取数据,标准C库中提供了多个读取函数来满足用户的不同需求,这些函数大体分为三类:字符读取(fgetc)、按行读取(fgets)、按块读取(fread)。
按字符读取fgetc
头文件
include <stdio.h>
函数原型
int fgetc(FILE * stream);
int getc (FILE * stream);//功能等效与fgetc,,但通过宏定义实现
int getchar (void);
功能:获取一个指定文件的字符,并在读取一个字节后将光标位置向后移动一个字节;
成功:返回读到的字符的ASCII;失败:EOF(读到文尾或错误);
按行读取fgets
通过C99标准可以知道该函数的作用是从文件指针stream指向的文件中读取一行字符,并把读取的字符存储在指针s所指向的字符串内,当读取到n-1个字符、或者已经读取到文件末尾(EOF)、或者读取到换行符’\n’时,则函数调用停止。
头文件
#include <sys/ioctl.h>
函数原型
char * fgets(char *s,int size ,FILE *stream);
char * gets(char *s);//缺省后自动从stdin 读取文件
成功:返回自定义缓冲区指针;
失败:NULL(读到文尾或错误);
s:自定义缓冲区指针
size :自定义缓冲区大小
stream:即将被读取数据的文件指针
关于缓冲区
用户调用fopen打开文件之后,可以把数据写入到文件中以及从文件中读取数据,但是实现读取和写入的过程中其实内核并没有直接操作文件,而是在操作指向文件的结构体指针FILE,也就是用户写入的数据和读取的数据会先存储在FILE结构体的*缓冲区*中,当用户调用刷新缓冲区的函数或者其他读写函数时,FILE结构体的缓冲区会被刷新,数据才会被系统写入文件
每当使用标准IO的读操作函数,试图将数据从文件 a.txt读取出来时,数据都会流过标准*输入**缓冲区*,然后再在适当的时刻冲洗(或称刷新,flush)到内核缓冲区,最后才真正得到数据。
缓冲区的出现其实就是由于输入设备和输出设备对于数据的读写速度比较慢,其实就是CPU为了降低输入输出次数,目的是为了提高运行效率,避免长时间的等待,所以内核就在内存中提供了一块空间作为缓冲区,缓冲区也可以称为缓存(Cache),是属于内存空间的一部分。
根据IO设备的不同,可以把缓冲区分为输入缓冲区和输出缓冲区,同样,根据刷新形式的不同,可以把缓冲区分为三种:全缓冲、行缓冲、无缓冲。
全缓冲:指的是当缓冲区被填满就立即把数据冲刷到文件、或者在关闭文件、读取文件内容以及修改缓冲区类型时也会立即把数据冲刷到文件,一般读写文件的时候会采用。
无缓冲:指的是没有缓冲区,直接输出,一般linux系统的标准出错stderr就是采用无缓冲,这样可以把错误信息直接输出。
行缓冲:指的是当缓冲区被填满(一般缓冲区为4KB,就是4096字节)或者缓冲区中遇到换行符’\n’时,或者在关闭文件、读取文件内容以及修改缓冲区类型时也会立即把数据冲刷到文件中,一般操作IO设备时会采用,比如printf函数就是采用行缓冲。
全缓冲和行缓冲除了以上几种情况外,当程序结束时缓冲区也会被刷新,另外,也可以采用函数库中的fflush函数手动刷新缓冲区。
对于标准输出stdout而言默认是采用行缓冲的,而对于标准出错stderr而言默认是采用无缓冲的,对于普通文件而言默认是采用全缓冲的。
fflush
/*头文件:*/
#include <stdio.h>
/*函数原型*/
int fflush(FILE *stream);
按块读取fread
头文件
#include <sys/iotcl.h>
函数原型
size_t fread (void *ptr,size_t size,size_t nmemb,FILE *stream);
成功:返回读取的数据块个数(等于nmemb);失败:读取的数据块个数(小于nmemb或等于0)||(已达文尾或错误)
ptr:自定义缓冲区指针
size:数据块大小
nmemb:数据块个数
stream:即将被读取数据的文件指针
判断文件已到末尾还是出错feof/ferror
头文件
#include <stdio.h>
函数原型
int feof(FILE *stream);//读到文尾时为真
int ferror(FILE *stream);//出错时为真
写入文件
字符写入
头文件
#include <stdio.h>
函数原型
int fputc (int c ,FILE *stream);
int putc (int c,FILE *stream);
int putchar(int c);
成功:写入到的字符;失败:EOF
c:要写入的字符
stream:写入的文件指针
按行写入
头文件
#include <sys/ioctl.h>
函数原型
int fputs(const char *s,FILE *stream);
int puts(const char *s);
成功:非负整数;失败:EOF
s:自定义缓冲区指针
stream:即将被写入数据的文件指针
按块写入
头文件
#include <sys/ioctl.h>
函数原型
size_t fwrite(const void *ptr,size_t size,size_t nmemb,FILE *stream);
成功:返回写入的数据块个数(等于nmemb);失败:写入的数据块个数(小于nmemb或等于0)||(已达文尾或错误)
ptr:自定义缓冲区指针
size:数据块大小
nmemb:数据块个数
stream:即将被写入数据的文件指针
文件位置
设置位移fseek
头文件
#include <sys/ioctl.h>
函数原型
int fseek (FILE *stream ,long offset,int whence);
功能:设置指定文件的当前位置偏移量
stream :需要设置位置偏移量的文件
offset: 新位置偏移量相对基准点的位移
whence:基准点
SEEK_SET:文件开头
SEEK_CUR:当前位置
SEEK_END:文件末尾
获取位移
头文件
#include <sys/ioctl.h>
函数原型
long ftell(FILE *stream);
成功:当前文件偏移量;失败:-1;
stream :需要返回当前文件位置偏移量的文件指针
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)