一、概念
标准IO是有缓存的IO,文件IO没有缓存,适合于通信、硬件设备操作
标准IO是库函数,文件IO是系统调用
文件 IO 与标准 IO(基于 C 库函数的 IO)是 Linux 中两种主要的 IO 方式,二者的核心差异如下:
特性 | 文件 IO(系统调用) | 标准 IO(库函数) |
---|---|---|
缓存机制 | 无用户空间缓存,依赖内核缓存 | 有用户空间缓存(全缓存、行缓存等) |
接口类型 | 系统调用(如 open、read、write) | 库函数(如 fopen、fread、fwrite) |
效率 | 频繁调用时效率较低(系统调用开销) | 效率高(缓存减少系统调用次数) |
实时性 | 实时性好(直接与内核交互) | 实时性差(缓存延迟刷新) |
适用场景 | 底层开发、实时性要求高的场景 | 普通文件操作、追求开发效率的场景 |
二、系统调用与库函数
系统调用:是Linux内核中的代码,只能在Linux系统中使用
库函数:是对系统调用的封装,可以在不同的操作系统中安装并使用,库函数最终还是要调用系统调用完成对应功能
三、文件IO函数接口
1. 函数接口:
标准IO 文件IO
fopen open
fclose close
fgetc/fputc read/write
fgets/fputs
fscanf/fprintf
fread/fwrite
fseek/ftell/rewind lseek
2. 文件打开
原型:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
功能:
打开文件,获得操作文件的 文件描述符
参数:
pathname
:要打开的文件路径flags
:打开文件的标志(必须包含O_RDONLY
/O_WRONLY
/O_RDWR
三者之一,可选辅助标志如下):O_RDONLY
:只读O_WRONLY
:只写O_RDWR
:读写O_CREAT
:文件不存在时创建(需配合mode
指定文件权限)O_TRUNC
:文件存在时,截断为 0(清空内容)O_APPEND
:写操作时追加到文件末尾O_EXCL
:与O_CREAT
配合,若文件已存在则报错
返回值:
- 成功:返回 新文件描述符(非负整数)
- 失败:返回
-1
注意:
- 有三个特殊的文件描述符:
- 标准输入:
0
- 标准输出:
1
- 标准错误:
2
- 标准输入:
- 文件描述符特点:
- 是 非负整数;
- 取值为 尚未被占用的最小非负整数;
- 存在上限,到达上限后再打开文件会报错。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>int main(void)
{int fd = 0;// // close(0); //关闭输入流// getchar();// // close(1);// printf("hello");//0664 //八进制//110110100//rw-rw-r--//O_WRONLY: 00000001// O_CREAT: 00000100// O_TRUNC: 00001000// -------------------- |// flags: 00001101 // 所有标志位被合并起来fd = open("a.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);printf("fd = %d\n",fd); //[文件描述符]fd = 3 (从3开始)//0,1,2 被占用(有上限)if(-1 == fd){perror("fail to open");return -1;}//rfd = open("a.txt",O_RDONLY,0664);//r+fd = open("a.txt",O_RDWR,0664);//Wfd = open("a.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);//w+fd = open("a.txt",O_RDWR | O_CREAT | O_TRUNC,0664);//afd = open("a.txt",O_WRONLY | O_APPEND | O_CREAT,0664);//a+fd = open("a.txt",O_RDWR | O_APPEND | O_CREAT,0664);close(fd);return 0;
}
3. 关闭文件描述符
原型:
int close(int fd);
功能:
关闭文件描述符
4. 标准 I/O 对应的文件 I/O 的打开方式
标准 I/O | 文件 I/O 打开方式 | ||
---|---|---|---|
r | O_RDONLY | ||
r+ | O_RDWR | ||
w | `O_WRONLY | O_CREAT | O_TRUNC, 0664` |
w+ | `O_RDWR | O_CREAT | O_TRUNC, 0664` |
a | `O_WRONLY | O_APPEND | O_CREAT, 0664` |
a+ | `O_RDWR | O_APPEND | O_CREAT, 0664` |
5. 文件 I/O 读写
1. write
原型:
ssize_t write(int fd, const void *buf, size_t count);
功能:
向文件描述符 fd
中,写入 buf
指向的 count
个字节 的数据
参数:
fd
:文件描述符buf
:要写入的数据空间 首地址count
:要写入的 字节数
返回值:
- 成功:返回 实际写入的字节数
- 失败:返回
-1
四、实战练习
//图片拷贝#include<stdio.h>
#include<string.h>int main(void)
{FILE *fp1 = NULL;FILE *fp2 = NULL;size_t nret = 0;char pic[4096] = {0};fp1 = fopen("pp1.png","r");fp2 = fopen("dst.png","w");if(fp1 == NULL || fp2 == NULL){perror("fail to fopen");return -1;}while(1){nret = fread(pic,1,sizeof(pic),fp1);if(nret == 0){break;}fwrite(pic,1,nret,fp2);// fwrite(pic,nret,1,fp2);}fclose(fp1);fclose(fp2);return 0;
}
//2. 统计一个文件中出现最多的字符是哪个?出现了多少次?// + 使用链表实现// + 使用数组实现// 0 - 255 cnt[256]// 'a' -> cnt[97]#include<stdio.h>
#include<string.h>int main(void)
{FILE *fp = NULL;char file[256] = {0};int ch[256] = {0};int i = 0;printf("请输入文件的名字:\n");fgets(file,sizeof(file),stdin);file[strlen(file)-1] = '\0';fp = fopen(file,"r");if(NULL == fp){perror("fail to fopen");return -1;}while(1){i = fgetc(fp);if(EOF == i){break;}ch[i]++;}fclose(fp);int max = 0;for(i = 0;i < 256;i++){if(ch[i] > ch[max]){max = i;}}for(i = 0;i < 256;i++){if(ch[i] == ch[max]){printf("文件中出现最多的字符是'%c'\n",(char)i); printf("其ascii码值为: %d\n",i);printf("出现了%d次\n",ch[i]);} }return 0;
}