ANSI C 定义了一组标准输入输出函数,在libc库中
- fopen
- fclose
- fread
- fwrite
- fgets
- fputs
- scanf
- printf 等等
上面的函数,应该都很熟悉,就不再多做介绍
标准I/O库是将一个打开的文件模型化为一个流,这个流其实就是一个指向FILE类型的结构 的指针,在程序开始之后,都会有三个打开的流对应标准输入,标准输出,标准错误
#include <stdio.h> //文件描述符
extern FILE *stdin; 0
extern FILE *stdout; 1
extern FILE *stdrr; 2
FILE的流其中包括了文件描述符和缓冲区,对应的文件描述符如下:
/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO 1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */
而缓冲区,则和前面介绍的RIO是一样的目的,
在linux下,如果你使用系统调用和标准I/O库函数来实现同样的功能,你会发现 系统调用的性能比库函数要低得多,这是因为系统调用时,Linux必须从运行用户 代码切换执行内核代码,然后再返回到用户代码,频繁系统调用会影响系统的性 能,而标准I/O函数使用缓冲区来避免过多的系统调用
例子:
用户程序使用fgetc函数时,fgetc会在打开的文件分配一个缓冲区来加速读写,
在用户第一次调用时,通过系统调用进入内核填满缓冲区,然后后面的fgetc调用
返回的数据会在缓冲区中得到,如果缓冲区被清空,再继续系统调用填满,这样
在用户空间读取数据比在内核读数据块得多,所以性能要好一些。
C标准库的I/O缓冲区有三种类型:
- 全缓冲 如果缓冲区写满了就写回内核。常规文件通常是全缓冲的
- 行缓冲 如果用户程序写的数据中有换行符就把这一行写回内核,或者如果缓冲区写满了就写回内核。标准输入和标准输出对应终端设备时通常是行缓冲的
- 无缓冲 用户程序每次调库函数做写操作都要通过系统调用写回内核。标准错误输出通常是无缓冲的,这样用户程序产生的错误信息可以尽快输出到设备