一、关于标准IO缓冲区
标准IO提供缓冲的目的是尽可能减少使用read和write调用的此数,他对每个IO流自动地进行缓冲管理。标准IO提供三种类型的缓冲:
1、全缓冲:这种情况下,当标准IO缓冲区填满后才进行实际IO操作。在一个流上执行第一次IO时,相关标准IO函数通常调用malloc获得所需的缓冲区。全缓冲的缓冲区大小一般为8192(具体要看设置)
2、行缓冲:当输入和输出中遇到换行符‘\n’时,才会执行实际IO操作。当涉及一个终端时(例如标准输入和标准出错),通常使用行缓冲。
因为标准IO库用来收集每一行的缓冲区的长度是固定的,所以只要行缓冲区满了,即使还没有写一个换行符,也会进行IO操作
3、不带缓冲:标准IO库不对字符进行缓冲存储,只要执行了输入和输出操作,便会立即实行IO操作。标准出错stderr通常是不带缓冲的。
对于进程预定义了三个流,并且这三个流可以自动地被进程使用:
标准输入:stdin
标准输出:stdout
标准出错:stderr
ISO C要求下列缓冲特征:
当且仅当标准输入和标准输出并不涉及交互式设备时,它们才是全缓冲。否则一般为行缓冲。
人机交互要求不可全缓冲。
标准出错绝不会是全缓冲的
涉及终端设备的其他流,一般为行缓冲的,否则是全缓冲。
普通文件一般为全缓冲
可以使用下面两个函数更改缓冲类型:
void setbuf(FILE *stream, char *buf);
功能:更改流的缓冲类型参数:stream:要更改缓冲类型的流指针buf:缓冲区的长度,通常指定为BUFSIZ,通常在此之后流就是全缓冲的。如果为NULL,则关闭缓冲。返回值:成功返回0,错误返回非0值
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
功能:更改流的缓冲类型参数:stream:要更改缓冲类型的流指针buf:如果被设置为不带缓冲的流,则忽略buf和size,如果指定了全缓冲或行缓冲,buf指定了缓冲区的地址,size指定了缓冲区的长度。如果buf为NULL,系统自动分配全缓冲区或行缓冲区合适的长度。mode:指定所需的缓冲类型_IOFBF 全缓冲_IOLBF 行缓冲_IONBU 不带缓冲size:缓冲区大小返回值: 成功返回0,错误返回非0值
int fflush(FILE *stream);
功能:冲洗一个流,此函数使该流所有未写的数据都被传送至内核参数:stream:要冲洗的流,如果为NULL,则冲洗所有输出流返回值:成功返回0,失败返回EOF
冲洗说明标准IO缓冲区的写操作,flush有两种意思,在标准IO库方面,flush意味着将缓冲区的内容写到磁盘上。在终端驱动程序方面,flush表示丢弃已存储在缓冲区的数据
二、流的定向
对于ASCII字符集,一个字符用一个字节表示,对于国际字符集,一个字符可用多个字节表示。标准IO文件流可用于单字节或多字节(宽)字符集。流的定向决定了所读写的字符是单字节还是多字节。当一个流最初被创建时,它并没有定向。如若在未定向的流上使用一个多字节IO函数,则将该流的定向设置为宽定向。如若在未定向的流上使用一个单字节IO函数,则将该流的定向设置为字节定向。
可用以下函数设置流的定向:
int fwide(FILE *stream, int mode);
stream: 要改变定向的流功能:设置一个未定向流的定向参数:
mode:为负值时,试图将指定的流设置为字节定向为正值时,试图将指定的流设置为宽定向为0时,不设置流的定向,但返回标示该流定向的值
返回值:若流是宽定向的则返回正值,若流是字节定向的则返回负值,若流是未定向的,则返回0。无出错返回注:fwaid只能改变未定向的流。并不改变已定向的流
三、标准IO的一些函数
FILE *fopen(const char *path, const char *mode);
功能:打开一个指定文件,返回一个标准IO流参数:path:文件所在路径mode:打开方式r:只读方式打开,打开后从文件头开始读r+:读写方式打开, 打开后从文件头开始读写w:只写方式打开,文件不存在则创建,存在则把文件截短至0,即将文件清空w+:读写方式打开,文件不存在则创建,存在则把文件截短至0,即将文件清空a:只写打开,文件不存在则创建,存在以只写方式追加,即从文件尾部开始写a+:读写方式打开,文件不存在则创建,存在则读文件时从文件头开始,写文件时从文件尾开始
当指定参数b时,表示以二进制方式打开,不过因为UNIX不对文本文件和二进制文件进行区分,所以在UNIX环境下指定b实际上并无作用
返回值:成功返回流指针,失败返回NULL
FILE *freopen(const char *path, const char *mode, FILE *stream);
path:文件所在路径功能:在一个指定的流上打开一个指定的文件,如若该流已经打开,则先关闭该流。若该流已经定向,则freopen清除该定向。此函数一般用于将一个指定的文件打开为一个预订义的流:标准输入,标准输出或标准出错。参数:
mode:
stream:要在此流上打开文件r:只读方式打开,打开后从文件头开始读r+:读写方式打开,打开后从文件头开始读写w:只写方式打开,文件不存在则创建,存在则把文件截短至0,即将文件清空w+:读写方式打开,文件不存在则创建,存在则把文件截短至0,即将文件清空a:只写打开,文件不存在则创建,存在以只写方式追加,即从文件尾部开始写a+:读写方式打开,文件不存在则创建,存在则读文件时从文件头开始,写文件时从文件尾开始当指定参数b时,表示以二进制方式打开,不过因为UNIX不对文本文件和二进制文件进行区分,所以在UNIX环境下指定b实际上并无作用
返回值:成功返回流指针,失败返回NULL
FILE *fdopen(int fd, const char *mode);
和fopen一样,不过此函数为写打开时,并不将文件清空。另外追加方式也不能创建该文件(因为文件已经存在)功能:将一个现有的文件描述符和一个标准IO流相结合参数:fd:一个已经打开的文件描述符mode:
返回值: 成功返回生成的流指针,失败返回NULL注:此文件描述符必须是一个已经打开的文件描述符
四、标准IO读写
int fgetc(FILE *stream);
功能:从指定的流中丢读取字符参数:stream:要读取的流返回值:成功返回字符,失败或读到文件尾部返回EOF(-1)
int fputc(int c, FILE *stream);
功能:向指定的流中写一个字符参数:
c:要写入的字符stream:要写入的流
返回值:成功返回写的字符,错误返回EOF
char *fgets(char *s, int size, FILE *stream);
功能:从指定的流读取多个字符存放在s指向的地址,每次读一行,以一个换行符终止参数:s:将读取到的数据存放到s中size:缓冲区长度stream:要读取的文件流返回值:成功返回s,失败或读到结尾返回NULL注:
- 每次fgets最多只能读取size-1个字符,因为每次读取结束时都会自动加‘\0’
- 如果读取过程中遇到‘\n’,则读取结束,'\n'会被读走
int fputs(const char *s, FILE *stream);
功能:将字符串写到指定的流参数:s:s中存放将要写入的数据stream:要写的文件流返回值:成功返回写入的字符个数,失败返回EOF注:如果遇到‘\n’则结束写
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从指定的流读取多数据存放在ptr指向的地址参数:ptr:将已读取的数据存放到ptr中size:要读取对象的大小nmemb:要求读取对象的个数stream:要读取的流返回值:返回实际读取的对象的个数
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
功能:将数据写向指定的流参数:ptr:存放要写入的数据存放在ptr中size:要写入数据的对象的大小nmemb:要求写入数据的对象的个数stream:要写入的流返回值:返回实际写入的对象的个数,如果返回值小于所要求的nmemb,则出错
注:
1、在上面的三个读操作中,不区分出错和到达文件尾,为了区分这两种情况,需调用以下两个函数
int feof(FILE *stream);int ferror(FILE *stream);两个函数的返回值:若条件为真则返回非0值。否则返回0
2、在大多数实现中,为每个流在FILE对象中维持了两个标志:
- 出错标志
- 文件结束标志
void clearerr(FILE *stream);
3、从流中读取数据以后可以调用ungetc将字符再压送回流中
int ungetc(int c, FILE *stream);
参数:c:要回送的字符
stream:要回送的流
返回值:成功返回c,出错返回eof
压送回流中的字符以后又可从流中读出。ISO C允许实现支持任何次数的回送,但是它要求时限提供一次只送回一个字符,我们不能期望一次能送回多个字符
回送的字符不必一定是上一次读到的字符,参数c既可以是上次读出的字符,也可以是任意别的字符,但不能回送EOF。但是当已经到达文件尾端时,仍可以回送一个字符,下次读将返回该字符,再次读则返回EOF。之所以能这样做的原因是一次成功的ungetc调用会清除该流的文件结束标志。
五、文件定位
int fseeko(FILE *stream, off_t offset, int whence);
int fseek(FILE *stream, long offset, int whence);
功能:更改内核中offset的值参数:stream:要更改的文件流offset:偏移值。offset>0,向后偏移,offset<0,向前偏移。whence:SEEK_SET 从文件其实位置开始SEEK_CUR 从文件当前位置开始SEEK_END 从文件尾端开始返回值:成功返回0,失败返回-1注:上述两个函数的区别仅在于文件偏移量的类型不一样,一个时是long,一个是off_t
off_t ftello(FILE *stream);
long ftell(FILE *stream);
功能:获得内核中的文件偏移量参数:stream:要获取偏移量的文件流返回值:成功返回文件从头开始的偏移值,失败返回-1注:上述两个函数的区别仅在于文件偏移量的类型不一样,一个时是long,一个是off_t
void rewind(FILE *stream);
功能:定位到文件起始位置参数:stream:要定位的文件流
int fileno(FILE *stream);
功能:获得与流相关联的文件描述符参数:stream:要获取描述符的流返回值:返回与流相关联的文件描述符
六、临时文件
char *tmpnam(char *s);
功能:产生一个与现有文件名不同的一个有效路径名字符串参数:s:如果为NULL,则将产生的路径名存放在一个静态区中。指向该静态区的指针作为函数值返回。下一次再调用该函数时,会重写该静态区。如果s不是NULL,则将产生的路径名存放在s指向的空间中,s作为函数返回值。返回值:指向唯一路径名的指针
FILE *tmpfile(void);
功能:创建一个临时二进制文件(wb+),在关闭文件或进程结束时 将自动删除这种文件返回值:成功返回文件流指针,出错返回NULL