五、每次一行的IO
上一篇总结到了标准IO库中,单个字符的IO操作。紧接上篇,Unix中提供了两个 以行为单位操作的IO:
#include<stdio.h>
char *fgets(char *restrict buf, int n,FILE* restrict fp);
char *gets(char *buf);
返回值:若成功,返回buf;若出错或到文件尾端,返回EOF
gets 是从标准输入读,fgets 是从指定的文件流中读。
书中对这两个函数进行了介绍,注意:不建议使用gets这个函数!!!新的 ISO C 标准中已经不用gets这个接口了
在上述中,有一句话“读入的字符送入缓冲区,该缓冲区以null字符结尾。”何为null字节????
其实就是我们常用的,字符串的结尾 '\0'
#include<stdio.h>
char *fputs(const char *restrict buf, int n,FILE* restrict fp);
char *puts(char *buf);
返回值:若成功,返回非负值;若出错,返回EOF
这两个函数与上述两个读函数对应,puts 是写到标准输出,fputs 写入指定文件流。puts不像gets那么不安全,但也不建议使用。
函数 fputs,是将一个以 '\0' 结尾的字符串写入到指定流中,并不是一次输出一行遇到 '\0' 就输出。
函数 puts,是将一个以 '\0' 结尾的字符串写入到标准输出中。
六、二进制的IO
由于fgetc 和 fputc 一次只能读取一个字符,fgets 和 fputs 遇到 '\0'就结束一次操作。对于读写二进制数组,或是结构都不是很好用。故引入fread 和 fwrite ,个人也是觉得这两个函数用的最多。
#include<stdio.h>
size_t fread(void *restrict ptr, size_t size, size_t objNum,FILE* restrict fp);
size_t fwrite(const void *restrict ptr, size_t size, size_t objNum,FILE* restrict fp);
返回值:返回读写的对象个数
书中介绍了以下两种运用场景:
fread 在读对象时,所返回的个数要是小于想要读取的 objNum ,则有可能是两种错误,要么出错要么到文件尾。故需要ferror 或 feof 去判断是何种错误。
fwrite 在写对象时,所返回的个数要是小于想要写入的 objNum,必是出错。
对于fread 和 fwrite而言,有一个致命的问题。那就是它只能用于在同一个操作系统上使用。在早期网络并不发达的环境中,这不算问题,但是现在许多异构系统通过网络连接起来,这个系统写数据,那个系统处理数据变的常见。故这两个函数不能使用。书中解释原因如下:
七、定位流
在定位流这里,书里介绍了三组函数,我只用过第一组。全部整理一下,也长长见识。
#include<stdio.h>
long ftell(FILE* fp);
返回值:若成功,返回当前文件位置指示;若出错,返回-1L
int fseek(FILE* fp, long offset, int whence);
返回值:若成功,返回0;若出错,返回-1
void rewind(FILE* fp);
以上这三个函数都是以字节为度量的
函数 ftell ,返回的是在当前的文件流的字节位置。
函数 fseek, 是将该流偏移offset个字节,从whence位置
SEEK_SET : 表示文件的开头;SEEK_CUR :表示文件的当前位置;SEEK_END:表示文件的结尾
函数 rewind,是将文件流位置放到文件的起始位置
其他两组直接截书中原图:
八、格式化IO
1、格式化的输出
总共有五个函数,如下:
通过函数的定义可以比较清楚的明白其作用,printf 是输出到 stdout ,其他的目标有的是流、有的是文件描述符。需要注意的是, 我个人比较喜欢用 sprintf ,将复杂的数据格式化成字符串时比较好用,现在应该尽量使用 snprintf ,要告诫自己注意缓冲区的大小,避免越界!!!
其格式化的方式,格式如下(有些没咋用用过,方便查找):
[flags] :
[fldwidth]:
[precision] :
[lenmodifier] :说明参数的长度
还有一套printf 族函数的变体函数,将可变参数表(...),替换成了 va_list arg
2、格式化输入
格式化输入总共有三个函数,是将流中的输入字符串,按照 format 格式,输出到参数列表中。
以上部分都是书中原文