分类: LINUX
2008-12-09 13:00:03
本章讲述ISO C的标准I/O库函数(定义在
ISO C中使用文件流的概念描述和操作磁盘文件
在实现了宽字符集的C99中,流的定向决定了在流中以单字节还是多字节读写字符。可使用fwide函数进行设置:
mode的取值为:
>0: 宽字节定向
<0: 字节定向
=0: 不设置,返回当前定向方式
返回值:
>0: 宽字节定向
<0: 字节定向(需先结合errno判断是否发生函数调用失败)
=0: 未定向
这是三个预定义的文件流指针,定义在
全缓冲(fully buffered): 缓冲区满时触发I/O;
行缓冲(line buffered): 遇到'\0'换行符或缓冲区满时触发I/O;
非缓冲(unbuffered): 直接触发I/O;
函数fflush用于立即冲洗指定的标准输出流,以NULL为输入参数时表示冲洗全部输出流:
行缓冲常用于tty、telnet等交互式命令行终端,它们的特点是通过换行回车结束字符串输入,即这种方式输入的字符串都以'\n'+'\0'结尾。不涉及交互时通常是权缓冲的;
当内核从行输入缓冲区取数时,将造成行输出缓冲马上被冲洗。一个例子是当前shell的后台作业执行结束时,只要键入(stdin)回车,作业完成的提示将马上出现在终端屏幕(stdout)上;
stderr的默认是非缓冲的方式输出的,ISO C规定stderr的输出不能为全缓冲;
进程正常终止(显式或隐式的调用了exit)时,所有的缓冲区将马上被冲洗;
设置缓冲方式的函数:
要求: ① 在fp已打开后才能调用;
② 在对流执行任何一个其它操作之前调用;
setbuf用于显式的为fp指向的文件流指定缓冲区为buf,缓冲区的长度必须为BUFSIZ(定义在
setvbuf通过mode指定缓冲类型,并可通过size指定buf的长度(建议是BUFSIZ)。当buf是NULL时,表示让系统来分配缓冲区;mode参数的选项包括了:_IOFBUF(全缓冲)、_IOLBUF(行缓冲)、_IONBUF(非缓冲);
打开
freopen用于将fp指向的流重定向到pathname上,类似dup2;
fdopen不是ISO C,它根据一个已打开的文件描述符filedes创建指向文件流的FILE指针,它常用于将文件流指针关联到已打开的管道或套接字;
参数type是个字符串,包括了"r"、"w"、"a"、"r+"、"w+"、"a+"。对于type参数,应注意:
在使用w或a选项时,若文件不存在则自动创建,新建文件的访问模式通过进程的umask限制;
后缀b(如rb、wb、……等)对UNIX无意义。
对于fdopen,选项w不能截文件为0,而由filedes的open函数决定;
r+和w+方式打开文件时,输出/输入之后必须等待冲洗或者改变流位置才能进行输入/输出;
若引用的文件是交互式终端,则默认打开方式为行缓冲,否则默认是全缓冲;
关闭
和close一样,进程结束时所有打开的文件流也被自动关闭;
读写
① 每次读/写一个字符到buffer:
getc和putc通常实现为宏,而fgetc和fputc不能实现为宏;
这几种读/写函数之间主要区别为:参数表达式、函数地址(宏函数无地址)、效率;
由于读函数在文件结束或出错时都将返回EOF,应通过以下两个函数返回值的真假作具体判断:
函数clearerr则用于清除文件流的EOF标志:
函数ungetc可将一个字符压(push)到流中:
下次getc时将再次读到这个字符,像栈的进出(push/pop)一样;
getchar和putchar使用的文件流分别为stdin和stdout;
② 每次读/写一行字符串到buffer:
读(输入):
fgets从指定的流读取n个字符(或者读到一个'\0')到stdin的buffer,buffer在满时往缓冲区的最后一格填充'\0';
gets函数带来缓冲区溢出(buffer overflow)的安全隐患,ISO C已经不推荐使用。现代的系统仍然将其实现只是为了向前兼容的考虑;
写(输出):
fputs将一个字符串送到指定的文件流,注意换行符'\n'需自己指定;
puts将指定的字符串送到stdout,并自动跟一个'\n'换行符(即总是换行,包括puts(""));
③ 直接I/O(也称二进制I/O,面向结构的I/O等)
fread从文件流fp读取nobj个记录到ptr中,其中每个记录的长度为size;fwrite则从ptr中取nobj个记录写到fp指向的文件流中,其中每个记录的长度为size。
返回值为实际读写的对象数。对于fread,返回值小于nobj时应通过feof或ferror判断结果,而fwrite则肯定是写失败;
注意:由于字节对齐方式以及字节顺序因编译器或体系结构而异,fread和fwrite容易造成二进制代码的不兼容;
ftell返回当前在文件流中的位置(以long为步长);
fseek以whence指定的起始位置,将当前位置重新定位在offset处,whence的含义同lseek;
rewind复位当前位置到SEEK_SET;
另有ftello和fseeko以off_t为步长,参数列表类似ftell和fseek;
fgetpos将文件流的当前位置存到pos处,而fsetpos将当前位置设置为pos;
① printf家族:格式化输出
printf家族函数分别把指定的格式化字符串format输出到标准输出stdout/文件流fp/字符缓冲区buf,其中snprintf是为解决sprintf的缓冲区溢出隐患的替代函数;
可以使用的格式化标记可参考K&R编写的《The C Programming Language》一书,典型的使用包括%4d, %3.2f, %*.3f等;
vprintf(3)等前缀了个v的变体使用可变参数列表va_list替代格式化标记参数;
它们的返回值都是实际输出的字符数;
② scanf家族:格式化输入
包括了scanf(3), fscanf(3), sscanf(3)及前缀了v使用va_list的变体,函数原型略;
使用时应注意输入必须和格式化的字符串匹配,否则第一个不匹配的字符后面的部分将被直接丢弃。
空白字符(空格、制表符等)均归为转义符'\s';
和fdopen互逆;
tmpnam创建了一个包含路径名的字符串存入prt,并返回其值。供其它函数创建临时文件,ptr为NULL时,这个路径名保存在系统分配的静态区中,可能会被多次重写;
tmpfile以wb+创建一个临时文件并返回其指针,在关闭该指针或者进程结束时这个临时文件将被自动删除;
SUS的XSI扩展也提供了两个创建临时文件的函数:
tempname在环境变量TMPDIR指定的目录下提供了一个以prefix指定为前缀的临时文件名,prefix只有效于最多前5个字符;
函数通过template生成一个临时文件,并打开之,返回其文件描述符。同时修改template为该文件的路径名。这个临时文件需要程序另行删除;
另有类似mkstemp的函数mktemp(2),对应的shell命令为mktemp(1),用于生成一个临时文件名,但不会创建之。