一、标准IO概念
标准IO在系统调用的上一层多加了一个缓冲区,也因此引入了流的概念,在UNIX/Linux下表示为FILE*(并不限于UNIX/Linux,ANSI C都有FILE的概念),FILE实际上包含了为管理流所需要的所有信息:实际I/O的文件描述符,指向流缓存的指针(标准I/O缓存,由malloc分配,又称为用户态进程空间的缓存,区别于内核所设的缓存),缓存长度,当前在缓存中的字节数,出错标志等。标准I/O对每个I/O流自动进行缓存管理,它提供了三种类型的缓存:
- 全缓存。当填满标准I/O缓存后才执行I/O操作。磁盘上的文件通常是全缓存的。
- 行缓存。当输入输出遇到新行符或缓存满时,才由标准I/O库执行实际I/O操作。stdin、stdout通常是行缓存的。
- 无缓存。相当于read、write了。stderr通常是无缓存的,因为它必须尽快输出。
二、行缓存的验证案例
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { printf("hello world!"); while(1) { sleep(1); } return 0; }
以上程序编译后,并不能输出任何信息。原因是使用printf输出hello world后,没有换行符。printf的缓冲是属于行缓冲的,输出遇到新行符或缓冲满时,才执行标准的I/O操作。此程序由于执行到了while中的循环,一直在循环。缓冲没有满,也没遇到换行符。所以屏幕无任何输出。
当去掉while循环,程序输出后立马结束,缓存中的信息就会输出出来。
三、FILE结构体
包含于#include <stdio.h>里,以下仅是FILE结构体部分参数,具体可查看头文件。
缓存的操作如下:
缓存遇到换行符或是return/exit(_exit不行) 或者写满缓存或者调用fclose后的时候,才会输出。
数据先写进缓存,然后再输出到文件或屏幕上。
stdin:标准输入,scanf 类函数就是默认的使用此函数
stdout:标准输出,printf 函数默认使用此
stderr:标准错误
这三个就是FILE 类型结构体指针,也称为流指针
四、函数格式定义
1. fopen()函数 – 用于打开一个文件,返回一个指向该文件的文件指针
#include<stdio.h> FILE* fopen(const char *filename, const char *mode);
- 函数描述:fopen 打开一个指定的文件。
- 参数说明:
filename:指定了被打开的文件的路径(相对路径或绝对路径) mode:指定了被打开文件的操作方式,如下: “r”:只读 “w”:只写,并将文件截断为0 “a”:只写,以追加方式从文件尾开始写 “r+”:读写 “w+”:读写,并将文件截断为0 “a+”:读写,以追加方式从文件尾开始写
- 函数返回值:
成功:指向FILE的指针 失败: NULL
2. fdopen()函数 – 把流与一个文件句柄相接
#include<stdio.h> FILE * fdopen(int fd, const char * mode);
- 函数描述:通俗的理解fdopen就是把参数fd的文件描述符转化为文件指针。
- 参数说明:
fd: 文件描述符 mode: 文件打开的模式。和fopen中的模式(如r-只读, w-写)相同。
- 函数返回值:
返回文件指针。
3. freopen()函数 --预定义的标准流文件定向到由path指定的文件中
#include <stdio.h> FILE *freopen( const char *path, const char *mode, FILE *stream );
- 函数描述:
实现重定向,把预定义的标准流文件定向到由path指定的文件中。标准流文件具体是指stdin、stdout和stderr。 其中stdin是标准输入流,默认为键盘;stdout是标准输出流,默认为屏幕;stderr是标准错误流,一般把屏幕设为默认。
- 参数说明:
path: 文件名,用于存储输入输出的自定义文件名。 mode: 文件打开的模式。和fopen中的模式(如r-只读, w-写)相同。 stream: 一个文件,通常使用标准流文件。
- 函数返回值:
成功,则返回一个path所指定文件的指针;失败,返回NULL。
4. fread()函数 – 用于从一个文件流中读取数据
#include<stdio.h> size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
- 函数描述:
它与底层调用read相似,其作用是从stream读取nitems个长度为size的数据到ptr所指向的缓冲区中。
- 参数说明:
ptr: 指定从文件流中读取的数据所存放的地方 size: 指定所读取的每一条记录的大小,单位字节 items: 指定本次读操作所读取的记录条数 stream: 指定读取数据的来源—文件流
- 函数返回值:
fread执行成功时返回实际读取记录的条数。
5. fwrite()函数 – 用于写数据到一个文件流中
#include<stdio.h> size_t fwrite(void *ptr, size_t size, size_t nitems, FILE *stream);
- 函数描述:
它与底层调用write相似,其作用是从stream写nitems个长度为size的数据到ptr所指向的缓冲区中。
6. fclosed函数
#include<stdio.h> int fclose(FILE *stream);
- 函数描述:
fclose操作将会引起所要关闭的文件流刷新缓冲区的操作,这使得该文件流上的所有读写操作都立刻执行。当程序正常终止时 (return/exit两个函数可以,_exit不行)会对所有尚未关闭的文件流自动执行fclose操作。
- 参数说明:
stream: 指定断开数据的来源—文件流
- 函数返回值:
成功返回0 失败返回EOF
7. fflush()函数
#include<stdio.h> int fflush(FILE *stream);
- 函数描述:
清除一个流,即清除文件缓冲区,当文件以写方式打开时,将缓冲区内容写入文件。也就是说,对于ANSI C规定的是缓冲文件系 统,函数fflush用于将缓冲区的内容输出到文件中去。
- 参数说明:
stream: 指定刷新数据的来源—文件流
- 函数返回值:
如果成功刷新,fflush返回0。指定的流没有缓冲区或者只读打开时也返回0值。 失败返回EOF指出一个错误。
8. fgetc、getc、getchar – 从指定文件流中读取一个字节的数据
#include<stdio.h> int fgetc(FILE *stream); int getc(FILE *stream); int getchar();
- 函数描述:
函数fgetc从指定的文件流中读取一个字节的数据,并返回该字节数据的整型值,当读到文件尾或发生错误时返回EOF。getc同 fgetc,只是它有可能被实现为宏。getchar函数相当于从标准输入读取字节时的fgetc。
- 参数说明:
stream: 指定获取数据的来源—文件流
- 函数返回值:
成功返回该字节数据的整型值。 失败返回EOF指出一个错误。
9. fputc、putc、putchar – 写一个字节数据到指定的文件流
#include<stdio.h> int fputc(int c, FILE *stream); int putc(int c, FILE *stream); int putchar(int c);
- 函数描述:
fputc函数将一个字节写到指定的文件流中,成功时返回返回写入的字节的整型值,失败时返回EOF。putc同fputc,只是有可能 被实现为宏。putchar相当于向标准输出写一个字节时的fputc。
- 参数说明:
stream: 指定写入数据的来源—文件流
- 函数返回值:
成功返回该字节数据的整型值。 失败返回EOF指出一个错误。
10. fgets、gets – 用于从一个文件流读取一个字符串
#include<stdio.h> char *fgets(char *s, int n, FILE *stream); char *gets(char *s);
- 函数描述:
fgets函数从指定的文件流指针中读取一个字符串,直到遇到换行符或者已经读了n-1个字符或者遇到文件EOF,它会在所读取的 数据结尾加上一个\0字符,然后放到s指定的位置。
- 参数说明:
stream: 指定读取数据的来源—文件流 s: 指定存放所读取的数据的位置 n: 指定读取数据的最大长度(包括结尾的\0字符)
- 函数返回值:
成功返回返回指向s的指针 失败返回NULL