对于标准I/O库,它们的操作是围绕流进行的。当用标准I/O库打开或创建一个文件时,我们已使一个流与一个文件相关联。
对一个进程预定义了三个流,并且这三个流可以自动地被进程使用,它们是:标准输入、标准输出和标准出错,对应的文件指针分别为stdin、stdout和stderr。
为了减少使用read和write的调用的次数,标准I/O库提供了三种类型的缓冲机制,分别为全缓冲、行缓冲和不带缓冲。
全缓冲:在填满标准I/O缓冲区后才进行实际I/O操作。
行缓冲:当在输入和输出中遇到换行符时,标准I/O库执行I/O操作。
不带缓冲:标准I/O库不对字符进行缓冲存储。
一般来说,标准出错是不带缓冲的,打开至终端设备的流是行缓冲的,其他所有流则是全缓冲的。这里要注意一点的是,全缓冲、行缓冲和不带缓冲只与流有关,要看流带不带缓冲,带怎样的缓冲,而与使用哪个标准I/O库中的函数无关。例如,不能认为使用了fgets函数就认为是行缓冲的。
1、打开流的函数
FILE *fopen(const char *restrict pathname, const char *restrict type);
2、判断出错或到达文件尾端的函数
int ferror(FILE *fp);
int feof(FILE *fp);
3、一次读一个字符的函数
int fgetc(FILE *fp);
4、一次写一个字符的函数
int fputc(int c, FILE *fp);
5、一次读一行的函数
char *fgets(char *restrict buf, int n, FILE *restrict fp);
6、一次写一行的函数
int fputs(const char *restrict str, FILE *restrict fp);
7、二进制I/O函数
size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
size_t fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
其中,size指定每个元素的长度,如sizeof(float)等。nobj指定要写的元素的个数。
8、定位流的函数
long ftell(FILE *fp);
int fseek(FILE *fp, long offset, int whence);
void rewind(FILE *fp);
int fgetpos(FILE *restrict fp, fpos_t *restrict pos);
int fsetpos(FILE *fp, const fpos_t *pos);
9、格式化I/O函数
int printf(const char *restrict format, ...);
int fprintf(FILE *restrict fp, const char *restrict format, ...);
int sprintf(char *restrict buf, const char *restrict format, ...);
int snprintf(char *restrict buf, size_t n, const char *restrict format, ...);
int scanf(const char *restrict format, ...);
int fscanf(FILE *restrict fp, const char *restrict format, ...);
int sscanf(const char *restrict buf, const char *restrict format, ...);
10、流与文件描述符
int fileno(FILE *fp);
高级I/O里面一项重要的技术是使用I/O多路转接。先构造一张有关描述符的列表,然后调用一个函数,知道这些描述符中的一个已准备好进行I/O时,该函数才返回。
1、select函数
int select(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds, struct timeval *restrict tvptr);
2、操作描述符集的函数
int FD_ISSET(int fd, fd_set *fdset);
void FD_CLR(int fd, fd_set *fdset);
void FD_SET(int fd, fd_set *fdset);
void FD_ZERO(fd_set *fdset);
注意,声明了一个描述符集后,必须用FD_ZERO清除其所有位,然后在其中设置我们关心的各个位。
3、poll函数
int poll(struct pollfd fdarray[], nfds_t nfds, int timeout);
其中struct pollfd{
int fd;
short events;
short revents;
};
events表示描述符关心什么事件,revents表示描述符发生了什么事件。其中比较重要的三个值是POLLRDNORM、POLLWRNORM、POLLERR。