标准库中的I/O操作都是围绕流来操作的,而不是文件描述符。
流的定向
流的定向决定了所读、写的字符是单字节还是多字节的。当一个流最初被创建时,它并没有定向。如果在未被定向的流上使用一个多字节的I/O函数<wchar.h>定义中的函数,则将该流设置为宽定向的。相反,如果在为定向的流上使用一个单字节函数,则是字节定向的。
与流定向相关的函数:
#include<stdio.h>
#include<wchar.h>
int fwide(FILE *fp, int mode)
mode值为负:fwide试图使指定的字节流是字节定向的;如果mode的参数为正: fwide将试图使指定的流是宽定向的。如若mode参数值为0,fwide将不试图设置流的定向,但返回标识该流定向的值
I/O缓冲区
I/O缓冲的目的是尽可能减少使用read和write调用的次数(频繁调用这两个系统调用会耗费不少运行时间),因此,当缓冲区满了的时候才调用读写函数是一种减少系统调用折中方法。
标准I/O提供了3种类型的
- 全缓冲
适用于与磁盘等块设备交互场景。全缓冲是指,当缓冲区满了的时候才会调用读写系统调用,其他非满的时候,可以使用fflush刷新到磁盘。
- 行缓冲
适用于与终端交互的场景,一般涉及到标准输入和标准输出,使用的都是行缓冲。行缓冲也是一块长度固定的内存,当行缓冲捕捉到’\n’字符的时候,会刷新到输入输出设备。或者,当行缓冲满了的时候,也会调用读写系统调用。
- 无缓冲
无缓冲没有缓冲机制,也就是说直接调用读写调用。
涉及到缓冲的操作函数:
#include<stdio.h>
void setbuf(FILE *restrict fp, char *restrict buf)
int setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size)
setbuf用于为打开的文件流指定缓冲区。buf为一个缓冲区指针
setvbuf与setbuf在setbuf的基础上进行了功能扩展,mode表示所指向的缓冲类
mode:
-
_IOFBF 全缓冲
-
_IOLBF 行缓冲
-
_IONBF 不带缓冲
如果指定了一个带缓冲的流,而buf是空的,那么函数会自动分配一个长度为size的缓冲区
与流相关的操作
(1)打开
#include<stdio.h>
FILE *fopen(const char *restrict pathname, const chr *restrict type)
FILE *freopen(const char *restrict pathname, const chr *restrict type,FILE* restrict fp)
FILE *fopen(int fd, const char *type)
fopen不用多数,freopen在一个指定的流上打开一个指定的文件,如果该流已经打开,则先关闭该流。如果该流已经定向,则使用freopen清除该定向。此函数一般用于将一个指定的文件打开一个预定义的流:标准输入、标准输出和标准错误。
fdopen为一个文件描述符寻找一个缓冲区。这些文件描述符可能从(open,dup,dup2,fcntl,pipe,socket,socketpair或accept)函数得到。此函数常用语由创建管道和网络通信函数返回的描述符,因为这些描述符不能标准I/O函数fopen打开,所以必须先调用设备专用函数以获得一个文件描述符,然后fdopen使一个标准I/O流与该描述符相结合。
-type | open(2)- |
---|---|
r或rb | O_RDONLY |
w或wb | O_WRONLY | O_CREAT|O_TRUNC |
a或ab | O_WEONLY | O_CREAT | O_APPEND |
r+或r+b或rb+ | O_RDWR |
w+或w+b或wb+ | O_RDWR | O_CREAT | O_TRUNC |
a+或a+b或ab+ | O_RDWR | O_CREAT | OAPPEND |
(2)关闭
int fclose(FILE* fp);
(3)I/O标准库中的读写操作
#include<stdio.h>
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);
getc(stdin)和getchart()效果相同。getc和fgetc的区别在于,前者可被用于宏定义,而后者只能被作为函数调用。也就是说fgetc的地址可以作为参数传递个其他函数,而getc不能。
当函数调用出错或到达文件尾端时,三个函数的返回值相同,因此需要配合下面两个函数进行判断:
#include<stdio.h>
int ferror(FILE *fp); //如果流读写出错,则返回1,否则返回0
int feof(FILT *fp); //如果流到达缓冲区末尾,则该函数返回1,否则返回0
void clearerr(FILE *fp); // 清楚FILE结构体中上述两个标志
使用示例:
while((c=getc(stdin) != EOF))
if(put(c,stdout)==EOF)
err_sys("output error");
if(ferroe(stdin))
err_sys("input error");
(4) 每次一行I/O
#include<stdio.h>
char *fgets(char *restrict buf, int n, FILE *restrict fp);
char *gets(cahr *buf); //不推荐使用
int fputs(const cahr *restrict str, FILE *restrict fp);
int puts(const char *str);//不推荐使用
使用示例:
while(fgets(buf,MAXLINE,stdin) != NULL)
if(fputs(buf,stdout)==EOF)
err_sys("output error");
if(ferroe(stdin))
err_sys("input error");
(5)二进制读写
#include<stdio.h>
int fread(void *restrict ptr,int size, int nobj,FILE *restrict fp);
int fwrite(const coid *restrict ptr, int size, int nobj, FILE *restrict fp);
size是一次读写多少个字节,nobj是一次读写几次,函数返回的是一次读写了几个size大小的内容。
(6)定位
#include<stdio.h>
long ftelll(FILE *fp);
int fseek(FILE *fp, long offset, int whence);
void rewind(FILE *fd);
whence:
- SEEK_SET 文件开头
- SEEK_CUR 当前位置
- SEEK_END 文件末尾