标准IO库是在系统调用下进行了一层封装,实现了更多的文件操作函数。虽然它的内部同样是调用系统函数,但由于他的用户缓冲区的原因,它的效率在大多数情况下都要比系统调用高。
常用函数
fopen()
#include <stdio.h> FILE *fopen(const char *path, const char *mode);
mode | 说明 | 对应于open函数的flag值 |
r | 只读 | O_RDONLY |
r+ | 可读可写 | O_RDWR |
w | 只写(如果文件存在就清空从头开始写,如果文件不存在就建立) | O_WRONLY|O_CREAT|O_TRUNC |
w+ | 可读可写(如果文件存在就清空从头开始写,如果文件不存在就建立) | O_RDWR|O_CREAT|O_TRUNC |
a | 只写,追加模式(如果文件不存在就建立) | O_WRONLY|O_CREAT|O_APPEND |
a+ | 可读可写追加模式(如果文件不存在就建立) | O_RDWR |
#include <stdio.h> size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); fread(buf, 1, 50, fq) 等价于 fread(buf, 50, 1, fq)
fseek()
#include <stdio.h> int fseek(FILE *stream, long offset, int whence);
ftell(), 获取文件当前的读写位置偏移量
#include <stdio.h> long ftell(FILE *stream);
feof(), )用于测试参数 stream 所指文件的 end-of-file 标志,如果 end-of-file 标志被设置了,则调用
feof()函数将返回一个非零值,如果 end-of-file 标志没有被设置,则返回 0。
#include <stdio.h> int feof(FILE *stream);
fflush(), 刷新用户缓冲区,即将用户缓冲区的数据强制刷新到内核缓冲区。
#include <stdio.h> int fflush(FILE *stream); // 参数 stream 指定需要进行强制刷新的文件,如果该参数设置为 NULL,则表示刷新所有的 stdio 缓冲区。
格式化输出
#include <stdio.h> int printf(const char *format, ...); int fprintf(FILE *stream, const char *format, ...); int dprintf(int fd, const char *format, ...); int sprintf(char *buf, const char *format, ...); int snprintf(char *buf, size_t size, const char *format, ...); // 超出的部分会被丢弃
格式化输入
#include <stdio.h> int scanf(const char *format, ...); int fscanf(FILE *stream, const char *format, ...); int sscanf(const char *str, const char *format, ...);
其他
- 每个进程都有独立的文件描述符表,文件描述符0,1,2是被系统分配了的(宏定义:
STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO),分别是标准输入,标准输出,错误输出, 对应于标准库,也有全局变量stdin, stdout, stderr 分别是该三个IO的FILE指针,我们可以根据这三个指针配置标准输入输出,错误输出。eg:
#include<stdio.h> int main(void) { int x = 0; printf("haha"); // 等价于fprintf(stdout, "haha"): scanf("%d", &x); // 等价于fscanf(stdin, "%d", &x); return 0; }
- 库函数在用户内存空间也实现了自己的缓冲区,我们称之为stdio缓冲区。
- setvbuf() , 设置stdio缓冲区模式,大小,起始地址
#include<stdio.h> int setvbuf(FILE *stream, char *buf, int mode, size_t size);
stream:FILE 指针,用于指定对应的文件,每一个文件都可以设置它对应的 stdio 缓冲区。
buf:如果参数 buf 不为 NULL,那么 buf 指向 size大小的内存区域将作为该文件的 stdio 缓冲区,因为stdio 库会使用 buf 指向的缓冲区,所以应该以动态或静态的方式在堆中为该缓冲 区分配一块空间,而不是分配在栈上的函数内的自动变量(局部变量)。如果 buf 等 于 NULL,那么 stdio 库会自动分配一块空间作为该文件的 stdio 缓冲区(除非参数 mode 配置为非缓冲模式)。
size:指定缓冲区的大小。
mode:参数 mode 用于指定缓冲区的缓冲类型,可取值如下:
_IONBF:不对 I/O 进行缓冲(无缓冲)。意味着每个标准 I/O 函数将立即调用 write()或者 read(),并且忽略 buf 和 size 参数,可以分别指定两个参数为 NULL 和 0。标准错误 stderr 默认属于这一种类型,从而保证错误信
- 息能够立即输出。
- _IOLBF:采用行缓冲 I/O。在这种情况下,当在输入或输出中遇到换行符"\n"时,标准 I/O 才会执行文件 I/O 操作。对于输出流,在输出一个换行符前将数据缓存(除非缓冲区已经被填满),当输出换行符时,再将这一行数据通过文件 I/O write()函数刷入到内核缓冲区中;对于输入流,每次读取一行数据。对于终端设备默认采用的就是行缓冲模式,譬如标准输入和标准输出。
#include<stdio.h> #include<stdlib.h> int main(void) { printf("Hello World\n"); // 该程序运行起来只会打印Hello world, haha打印不出来 printf("haha"); for (;;)sleep(10); return 0; }
_IOFBF:采用全缓冲 I/O。在这种情况下,在填满 stdio 缓冲区后才进行文件 I/O 操作(read、write)。对于输出流,当 fwrite 写入文件的数据填满缓冲区时,才调用 write()将 stdio 缓冲区中的数据刷入内核缓冲区;
- 对于输入流,每次读取 stdio 缓冲区大小个字节数据。默认普通磁盘上的常规文件默认常用这种缓冲模式。
- setbuf(), setbuf()函数构建与 setvbuf()之上,执行类似的任务
#include <stdio.h> void setbuf(FILE *stream, char *buf); 相当于 setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);(BUFSIZ 定义于头文件<stdio.h>中,该值通常为 8192)
setbuffer(),
#include <stdio.h> void setbuffer(FILE *stream, char *buf, size_t size); 相当于 setvbuf(stream, buf, buf ? _IOFBF : _IONBF, size);