IO概述
- I/O是Input/Output的缩写,指的是输入/输出。在计算机科学和工程领域,I/O是指计算机系统与外部环境或内部组件之间进行数据交换的过程和机制。
- 用户I/O
- 用户通过输入设备与计算机交互。例如,通过键盘输入文字、通过鼠标点击界面等。
- 用户通过输出设备接收计算机的反馈。例如,显示器显示图像、打印机输出文件等。
- 文件I/O
- 程序通过文件系统进行数据读写操作。例如,从硬盘读取文件数据、将数据写入文件等。
-
- 计算机通过网络接口与其他计算机或设备进行数据交换。例如,通过互联网下载文件、发送和接收电子邮件等。
- 设备I/O
- 计算机与各种外部设备之间进行数据传输。例如,读取USB存储设备的数据、与外部传感器通信等。
五层I/O模型概述
- 五层I/O模型是计算机系统中用于描述数据从应用程序到物理硬件的传输过程的模型。这个模型帮助理解数据在不同层次上的处理方式,以及每一层在I/O操作中的角色。
- 应用层(Application Layer)
- 系统调用层(System Call Layer)
- 文件系统层(File System Layer)
- 设备驱动层(Device Driver Layer)
- 硬件层(Hardware Layer)
IO函数的定义
标准IO函数
- 标准IO函数根据ANSI标准,对文件IO函数进行二次封装。例如:printf函数,scanf函数
- 标准IO函数最终依然会去调用文件IO函数实现数据的输入输出,提高了代码的移植性。
- 标准I/O函数通常使用缓冲区来临时存储数据。这些缓冲区可以是针对文件、标准输入、标准输出等的内存区域,用于暂时存储数据,以减少与文件或设备的直接交互次数,从而提高效率。
文件IO函数
- 文件IO函数由操作系统提供的基本函数,与操作系统绑定,可移植性较低,又称为系统调用
- 例如:读函数在Windows为ReadFile,在Linux中为read
- 文件IO函数涉及到用户空间到内核空间切换,cpu模式切换,C代码调用汇编指令等等,属于一种耗时操作。应该尽量减少对文件IO函数的使用。
- 若要直接操作内核,则必须要使用对应操作系统提供的系统调用函数。
标准IO函数
1. 流和指针
- 流是一个数据传输通道,用于在程序和外部资源(如文件、网络、设备)之间移动数据。流以连续字节流的形式表示数据的输入和输出。
1. 流的分类
-
标准流
- stdin:标准输入流,用于从键盘或另一个程序的输出中读取数据。scanf,getchar,gets默认使用的都是stdin对应的缓冲区
- stdout:标准输出流,用于向屏幕或另一个程序的输入中写入数据。puts,printf,putchar默认使用的都是stdout对应的缓冲区
- stderr:标准错误流,用于输出错误消息到屏幕或日志文件。
-
文件流
通过fopen()函数打开文件时,会创建一个文件流,提供与文件的接口,用于进行文件的读写操作。
2.流指针
- 流指针是一个指向FILE结构体的指针,用于标识和操作文件流。FILE结构体在C标准库中定义,包含有关文件流的信息,如文件描述符、缓冲区、当前位置等。
- FILE结构体由系统定义并维护,包含文件流的状态信息。程序员无需手动管理FILE结构体,只需通过标准库函数进行访问和操作。
2.FILE结构体
- ctags 是一个用于生成 C/C++ 等语言的标记文件的工具,这个文件可以帮助代码编辑器快速跳转到函数、变量、结构体的定义。
sudo apt-get install ctags
cd /usr/include
sudo ctags -R
在 ~/.vimrc 文件中添加以下配置,以便 vim 使用生成的标记文件。
set tags+=/usr/include/tags
- 查找
vi -t FILE
输入对应的数字并回车以查看 typedef struct _IO_FILE FILE; 的定义。
导航代码:
方法 1:将光标停留在要追踪的符号上,按下 Ctrl + ] 跳转到定义处。
方法 2:按下 Ctrl + 鼠标左键点击要追踪的内容。
返回上层:
方法 1:按下 Ctrl + t 返回到之前的代码位置。
方法 2:按 Ctrl + 鼠标右键。
- 查找结果
3.man手册
- man命令用于查看Linux系统中命令、函数和系统调用的详细文档,包括功能、参数、返回值及其他相关信息。
- 第一章:可执行程序或Shell命令
第二章:系统调用(内核提供的函数),如文件IO函数
第三章:库调用(程序库中的函数),如标准IO函数
范例
man 3 fwrite //在man手册的第二章查找fwrite函数
4. 标准流指针
- 在main函数运行之前,操作系统为我们定义好了三个标准流指针,用于处理标准输入、输出和错误输出。
- FILE* stdin
定义:标准输入流指针,通常与键盘输入缓冲区相关联。
功能:向终端输入的数据会放入到stdin对应的缓冲区中。可以通过stdin读取终端数据。
默认使用:scanf、getchar、gets默认使用的都是stdin对应的缓冲区。 - FILE* stdout
定义:标准输出流指针,通常与屏幕输出缓冲区相关联。
功能:希望输出到终端的数据会放入到stdout对应的缓冲区中。可以通过stdout将数据输出到终端。
默认使用:printf、putchar、puts默认使用的都是stdout对应的缓冲区。 - FILE* stderr
定义:标准错误输出流指针,通常与屏幕输出缓冲区相关联。
功能:标准错误输出流指针是无缓冲的。缓冲区大小是1字节,因此无需任何刷新方式。
用途:一般用于打印错误信息。防止缓冲区被错误阻塞,导致数据无法输出。perror函数通常使用stderr。
5. 标准IO函数
- fopen
功能
fopen函数用于打开一个文件,并返回一个指向FILE类型的指针,用于后续的文件操作。
原型
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
参数
pathname:指定要打开的文件的路径及名称。
mode:指定打开文件的方式,决定文件的读写权限和状态。
文件打开模式
r:以只读的方式打开文件。
文件指针定位在文件开头。
r+:以读写的方式打开文件。
文件指针定位在文件开头。
w:以只写的方式打开文件。
文件指针定位在文件开头。
如果文件不存在,创建新文件。
如果文件存在,清空文件内容。
w+:以读写的方式打开文件。
文件指针定位在文件开头。
如果文件不存在,创建新文件。
如果文件存在,清空文件内容。
a:以追加的方式打开文件。
文件指针定位在文件末尾。
如果文件不存在,创建新文件。
数据将写入文件末尾。
a+:以读写追加的方式打开文件。
文件指针定位在文件末尾。读则在文件开头(初始位置)//读指针和写指针为同一个
如果文件不存在,创建新文件。
数据将写入文件末尾。
成功:返回指向FILE对象的指针。
失败:返回NULL,并设置errno以指示错误类型。
- perror
- 功能:根据errno打印对应的错误信息;
- 原型:#include<stdio.h>
void perror(const char* s ); - 参数:
char* s:用于提示的字符串;一般填写报错的函数名字。
- fclose
功能:关闭文件,释放各种资源:缓冲区资源,文件描述符资源
原型: #include<stdio.h>
int fclose(FILE *stream);
参数: FILE* stream指定要啊关闭的文件对应的流指针
返回值:
成功返回0
失败,返回EOF(-1),更新errno
- fprintf
功能:将数据格式化输出到指定文件中
原型 #include <stdio.h>
// int printf(const char *format, ...);
//printf("hello %d%c%f%s%g \n\t\b\r", 10, 'a', 3.14, "abc", 2.1);
int fprintf(FILE *stream, const char *format, ...);
参数:
FILE *stream:指定要输出到哪个文件中,就填上文件对应的流指针。该流指针用写的方式打开;
char *format:输入到文件中的内容;格式化字符串,其中可以填字符,可以填占位符,可以填转义字符
......:不定参数,不定数据类型,不定数据个数,跟着前面的参数来决定。
返回值:
成功,返回成功被打印的字符个数;
失败,返回负数。
- fscanf
功能:从指定文件中格式化读取数据
原型:#include<stdio.h