1.标准IO函数解析
- IO是操作系统的基础
如果没有IO操作,所有的系统文件将无法存储,更谈不上处理与分析,系统运行的结果也不为用户所见。
- 系统IO与与标准IO的区别
标准IO称为stdio,系统IO称为文件IO。系统IO是内核提供给用户处理IO操作的接口,标准C是不能处理输入输出问题的,必须借助内核提供的接口实现对program的输入输出处理。标准IO是在系统IO的基础上的二次封装,以屏蔽不同系统结构之间的差异,增加程序的可移植性。
2.文件指针FILE * 概述
FILE是一个结构体,主体有三部分:文件描述符(索引到对应的磁盘文件),文件读写指针,I/O缓冲区(内存地址)。
- 文件描述符
每个位置代表能打开一个文件,每打开一个新文件,则占用一个文件描述符,而且使用的是空闲的最小的一个文件描述符(3~1023)。
默认前三个是打开的,分别是标准输入(STDIN_FILENO)、标准输出(STDOUT_FILENO)、标准错误(STDERR_FILENO)。三者文件描述符分别为0、1、2。
- 为什么需要I/O缓冲区?
答:减少对磁盘的访问次数,提高程序操作文件的效率。内存和硬盘的访问速度不匹配,相差太大,假如没有缓冲区,每次直接从硬盘存取数据,则减慢了速度。
- 注意
linux系统函数没有缓存,要操作它(缓存),需要由用户提供。
为了提高程序效率,C库函数内部封装了一块缓存。
3.标准IO函数
3.1 fopen函数
3.1.1函数原型
- FLIE *fopen(const char *path,const char *mode)
3.1.2 头文件
- #include<stdio.h>
3.1.3参数
- const char *path :打开指定路径下的文件
- const char *mode:表示文件的打开方式
3.1.4mode
r | 只读方式打开,文件位置位于文件的起始处(文件必须存在) |
r+ | 以读写方式打开,文件位置位于文件的起始处(文件必须存在) |
w | 只写方式打开,若文件不存在则新建文件,若存在,则清空原有内容 |
w+ | 以读写方式打开,若文件不存在则新建文件,若存在,则清空原有内容 |
a | 只写方式打开,若文件不存在则创建文件,文件偏移量自动定位到文件末尾(以追加的方式写数据) |
a+ | 以读写方式打开,若文件不存在则创建文件,文件偏移量自动定位到文件末尾(以追加的方式写数据) |
3.1.5返回值
打开成功则返回FILE类型的指针,失败则返回空指针,并写入errno值。
简单示例:
#include <stdio.h>
int main(void)
{
FILE *fp = fopen("./a.txt", "r+");
if (fp == NULL)
{
perror("use fopen to open file fopen wrong");
return -1;
}
else
{
printf("use fopen to open file right\\n");
}
int flag = fclose(fp);
return 0;
}
3.2 fclose函数
3.2.1函数原型
- int fclose(FILE *fp)
3.2.2参数
- FILE *fp 打开的文件指针
3.2.3返回值
- 成功返回 0,如果失败,返回EOF,并且设置errno。
简单示例:
#include <stdio.h>
int main(void)
{
FILE *fp = fopen("./a.txt", "r+");
if (fp == NULL)
{
perror("use fopen to open file fopen wrong");
return -1;
}
else
{
printf("use fopen to open file right\\n");
}
int flag = fclose(fp);
if (!flag)
{
printf("关闭成功\\n");
}
else
{
printf("关闭失败\\n");
}
return 0;
}
3.3 fread函数
3.3.1 函数原型
- size_t fread(void *ptr,sizet_t size,size_t nmemb,FILE *stream);
3.3.2 参数
- ptr : 自定义缓冲区指针
- size :数据块大小(数据单元大小,如:1个单元5字节)
- nmemb:数据块个数 (读取2个单元,即两个单元,10个字节,实则返回数据单元数量)
- stream :即将被读取数据的文件指针
3.3.3 返回值
- 成功:成功读取的 “数据单元数量”,实际成功读取的字节数。
- 失败:读取的数据块的大小,小于nmemb或等于0。
3.3.4 举例
当使用 size_t ret = fread(buf, 1, 11, f_fd); 时,其中的 11 表示请求此次读取最多尝试读取 11 个字节(1024字节也如此)(因为 size=1,每个单元是 1 字节),如果文件中实际有效数据只有 10 字节(即 “超出 10” 的情况),fread会按以下逻辑处理:
1.实际读取字节数:
fread 会读取文件中全部的 10 字节数据(能读到多少就读多少),不会因为请求 11 字节而等待或报错。
2.返回值 ret:
返回实际成功读取的字节数 10(因为每个单元是 1 字节,返回值等于成功读取的字节数)。
3.缓冲区数据:
缓冲区 buf 中前 10 字节会被文件内容填充,第 11 字节及之后的内容不会被修改(如果是全局 / 静态缓冲区可能为 0,栈上的缓冲区可能是随机值,但这些都不是文件中的数据)。
关键结论:
fread 的第三个参数(此处为 11)是 “最大尝试读取的单元数”,而非 “必须读取的数量”。
当文件剩余数据不足时,函数会读取所有可用数据 并返回实际读取的数量(不会报错),这是一种安全的设计 —— 既不会因数据不足而失败,也不会读取到无效数据。
因此,使用 fread 时必须通过返回值判断实际读取的字节数,而不能假设一定能读到请求的数量。
3.4 fwrite函数
3.4.1 函数原型
- size_t fwrite(const void *ptr,size_t size,size_t nmemb,FILE *strem);
3.4.2 参数
- ptr : 自定义缓冲区指针
- size :数据块大小(数据单元大小,如每单元5个字节 一共10字节,那么就是2单元)
- nmemb:数据块个数 (实则写入的字节数,总单元数量)
- stream :即将被写入数据的文件指针
3.4.3 返回值
- 成功:实际成功写入的单元数量(看自己如何定义 若1个字节1单元,则为10单元,返回10)
- 失败:读取的数据块的大小,小于nmemb或等于0。
举例
3.5 fseek函数
3.5.1 函数原型
- int fseek(FILE *strem,long offset,int whence);
3.5.2 参数
- stream :需要设置位置便宜的文件指针
- offset :新位置偏移量相对基准点的偏移
3.5.3 whence
- SEEK_SET 文件开头
- SEEK_CUR 文件当前位置
- SEEK_END 文件末尾
3.5.4 返回值
- 成功:返回 0
- 失败:返回-1
举例:
3.6 获取/设置当前位置偏移量
3.6.1. 获取指定文件的当前位置偏移量
- 头文件 #include<sys/ioctl.h>
- 函数原型 long ftell(FILE *stream);
- 参数 stream:需要返回当前文件位置偏移量的文件指针。
- 返回值:成功:当前文件位置的偏移量 失败:-1
3.6.2 将指定文件的当前位置便宜量设置到文件开头处
- 头文件 #include<sys/ioctl.h>
- 函数原型 void rewind(FILE *stream);
- 参数 stream:需要设置偏移量的文件指针
总结
上述对标准IO的基本函数进行了展开的解析以及函数用例的简单例子的进行举例理解,举例分析为个人观点,如有错误之处,可以指出~完结✿✿ヽ(°▽°)ノ✿撒花
评论前必须登录!
注册