Linux学习笔记之标准IO
关于了解标准IO以及文件IO,首先我们通过以下简化的图了解一下文件系统的体系结构

系统调用:是操作系统提供的一组特殊接口,我们可以通过这一组接口,进行分配内存、创建进程、实现进程之间的通信等。
VFS:虚拟文件系统,是Linux文件系统对外的接口,一方面给用户空间的程序提供文件系统接口,另一方面还提供了内核中的一个抽象功能,实现不同文件系统在Linux下共存。一个实际的文件系统想被linux支持,就必须提供一个符合VFS标准的接口,才能与VFS协同工作,VFS不是实际操作系统,只是一种转换机制。它就是把各种具体的文件系统的公共部分抽取出来,形成一个抽象层,是系统内核的一部分,位于用户程序和具体的文件系统之间。
从图中我们知道,我们应用程序有两种方法对文件进行操作,一个是直接通过系统调用可以直接和内核进行交互,另一个是通过c库然后再通过系统调用对内核进行交互。
以下说一下文件IO和标准IO的区别
文件IO:又称为低级磁盘IO,任何兼容POSIX标准操作系统上都支持文件IO,每次执行操作时都会执行相关系统调用,不带缓冲,可以访问不同类型的文件。文件IO是对文件描述符进行操作
优点:直接处理实际文件。
缺点:频繁的系统调用,增加系统开销。
标准IO:又称为高级磁盘IO,遵循ANSIC相关标准,只要并发环境中有标准C库,标准IO就可以使用,带缓冲,通常只能访问普通文件。标准IO是对流进行操作。
优点:先读写缓冲区,然后必要时访问实际文件,减少系统调用,移植性好。
一.标准IO
标准IO是通过流进行操作从而达到对文件进行操作,那么流究竟是什么呢?
流其实是一个结构体类型的指针,一个指向文件的指针,是可以被我们当作操作文件的入口,以下是在/usr/include下找到流的原型
---------------------------------------------------------
补充:安装ctags插件
sudo apt-get update
sudo apt-get install ctags
cd /usr/include
sudo ctags -R 使ctags在当前目录下生效
vim -t 查找内容
---------------------------------------------------------




上面的结构体就是流的原型,所以我们在使用标准IO操作文件时用到的就是流。
标准IO下流的三种缓冲类型:
全缓冲:存满标准IO的缓冲区后才进行实际IO操作。默认打开都是全缓冲的。
何时能操作实际IO?
(1)缓冲区满
(2)使用fflush函数
(3)程序正常结束
行缓冲:输入输出遇到换行符时执行实际IO操作。例子:标准输入流和标准输出流。
何时能操作实际IO?
(1)缓冲区满
(2)使用fflush函数
(3)程序正常结束
(4)遇到换行符
无缓冲:不对IO操作进行缓冲,即在流读写时会立刻操作实际文件。例子:标准错误流。
流的常见操作:打开、读写、关闭
用户程序进行时,系统默认生成三个流,标准输入流(stdin)、标准输出流(stdout)、标准错误流(stderr)。
流的打开:有fopen()、freopen()、fdopen(),以不同形式打开文件,并且返回值都是一个指向流的指针,接下来主要讲fopen。
函数原型:FILE *fopen(const char *path, const char *mode);
函数功能:打开文件
函数头文件:#include <stdio.h>
函数参数:path:文件所在路径
mode:文件打开方式
r:用只读的方式打开,文件要一定存在
r+:可以对文件进行读写,文件要一定存在
w:用只写的方式打开,文件可以不存在,如果不存在,则创建文件,如果文件存在,就清空文件中的内容
w+:可以对文件进行读写,文件可以不存在,如果不存在,则创建文件,如果文件存在,就清空文件中的内容
a:用只写的方式打开,文件可以不存在,如果不存在,则创建文件,如果文件存在,在文件末尾追加
a+:可以对文件进行读写,文件可以不存在,如果不存在,则创建文件,如果文件存在,在文件末尾追加
函数返回值:成功:返回流(指向FILE的指针)
失败:返回NULL
流的关闭:fclose(),执行这个函数时总共进行两个步骤 ①将流的缓冲区内数据全部读入写入文件中 ②释放相关资源,关闭流
函数原型:int fclose(FILE *fp);
函数功能:关闭文件
函数头文件:#include <stdio.h>
函数参数:fp:准备关闭的流
函数返回值:成功:返回0
失败:返回EOF(-1),并置错误码
注:当标准IO执行结果如果出现错误时,会把错误码保存在全局变量errno中,然后使用perror函数进行打印错误信息。
流的读写:流的读写可以分做三小块,①fgetc和fputc ②fgets和fputs ③fwrite和fread
①fgetc和fputc 按字符读写(看最后一个字母就知道啦 c代表char)
函数原型:int fgetc(FILE *stream);
函数功能:从文件中读取一个字符
函数头文件:#include <stdio.h>
函数参数:stream:要读取的流;
函数返回值:成功:返回读到的字符
读到文件末尾或者失败:返回EOF(-1),并置错误码

fgetc内部会强转,所以最后返回的时字符。
函数原型:int fputc(int c,FILE *stream);
函数功能:向指定流输出一个字符
函数头文件:#include <stdio.h>
函数参数:
c : 需要输出的字符
stream:要指定的流;
函数返回值:成功:输出字符c
失败:返回EOF(-1)
fgetc和fputc结合起来使用文件复制代码如下

②fgets和fputs 按字符读写(看最后一个字母就知道啦 s代表string)
函数原型:int fgets(char *s , int size , FILE *stream);
函数功能:从流中读取取一行字符串,最多读取size-1字符。因为最后一个字符要放'\0',如果遇到换行符,则停止一次读取
函数头文件:#include <stdio.h>
函数参数:
s: 用来存放从文件中读取到的字符串缓冲区首地址
size : 获取的字符数(读取到最多为size -1)
stream:要指定的流;
函数返回值:成功:返回s
到达文件末尾或者失败:NULL
当一行内容大于等于size-1时,就读size-1个字符 ,否则读到换行符结束
函数原型:int fputs(const char *s , FILE *stream);
函数功能:向文件每次输入一行字符串
函数头文件:#include <stdio.h>
函数参数:
s: 用来存放从文件中读取到的字符串缓冲区首地址
stream:要指定的流;
函数返回值:成功:返回s
失败:NULL
fgets和fputs结合起来使用文件复制代码如下



浙公网安备 33010602011771号