闇の光

读书笔记 经验感受

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

标准I/O库(stdio标准输入输出)与它的头文件stdio.h提供了一个到底层I/O系统调用的通用接口。此标准库现在已经是ANSI标准C的一部分,我们前面所见到的系统调用都不是。标准I/O库提供了许多复杂的函数用来格式化输出以及扫描输入,另外它也负责处理设备的缓冲需求。

在许多方面,我们用使用底层文件描述符同样的方法来使用此标准库,我们只需要打开一个文件来建立一个访问通道,此操作所返回的值将作为其它I/O库函数的参数。与底层文件描述符相对应的对等物叫流(stream),它被实现为指向结构FILE的指针。

注意:不要将这些文件流同C++输入输出流(iostream)以及AT&T UNIX System V Release 3中引入的进程间通信STREAMS模型相混淆。

在程序开始时,有三个文件流是自动打开的,它们分别是:stdin、stdout以及stderr。它们都被定义在stdio.h中,分别表示标准输入、标准输出以及标准错误输出,并与底层文件描述符0、1、2相对应。

fopen

fopen函数是底层open系统调用的模拟,它主要用于文件和终端的输入输出。如果你需要对设备的输入输出进行明确的控制,最好去除底层系统调用,因为他们消除了来自库函数的不良副作用,比如输入输出缓冲。

函数的语法结构:

#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);

fopen打开被filename参数命名的文件,并将它同一个文件流关联起来。而mode参数则指定该文件是如何被打开的,它的设置内容为下列字符串之一:

"r" 或 "rb"以只读方式打开
"w" 或 "wb"以只写方式打开,并将文件长度截短至零
"a" 或 "ab"以只写方式打开,将内容附加到文件末尾
"r+" 或 "rb+" 或 "r+b"以更新方式打开(读操作和写操作)
"w+" 或 "wb+" 或 "w+b"以更新方式打开,并将文件长度截短至零
"a+" 或 "ab+" 或 "a+b"以更新方式打开,将内容附加到文件末尾

b表示文件是一个二进制文件而不是文本文件。

注意:同MS-DOS不同,UNIX和Linux不区分文本文件同二进制文件间的区别,它们对待所有的文件都是一样的,都把它们当作二进制文件看待。除此之外,还要注意mode参数必须是一个字符串,而不是一个字符。因此,通常使用双引号"r"而不是单引号'r'。

如果运行成功,fopen将返回一个非空File指针;若失败,则返回一个空值,该空值被定义在头文件stdio.h中。

可利用的文件流是有限的,同样文件描述符也是有限的,这个实际限制就是FOPEN_MAX,它通过头文件stdio.h来被定义,在Linux上通常至少为8以及比较典型的为16。

fread

fread函数被用来从一个文件流中读取数据,数据是从文件流stream被读取到由ptr所提供的一个数据缓冲区中的。fread和fwrite都是对数据记录进行处理,这些数据记录由记录大小size以及记录到传送的计数nitems来确定。函数将返回成功读取到数据缓冲区中的记录个数(而不是字节数),当到达文件尾时,它的返回值可能会小于nitems,包括零在内。

函数的语法结构:

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);

对所有向缓冲区里写数据的标准I/O函数来说,为数据分配空间和检查错误的工作是程序员本身的职责。详情将在以后的ferror和feof中了解。

fwrite

fwrite函数有一个同fread相似的接口,它从指定的数据缓冲区中得到数据,之后将它们写入到输出流中。它将返回成功写入的记录数目值。

函数语法结构:

#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);

注意:不推荐将fread和fwrite用于结构化数据,部分原因在于用fwrite所写的文件在不同的计算机之间可能不具备可移植性。

fclose

fclose函数关闭指定的文件流stream,使得所有未写出的数据都被写出。使用fclose非常重要,这是因为stdio库会对数据进行缓冲。如果程序需要确定数据是否完全被写入,就需要调用fclose。注意,当程序正常结束时,尽管所有依旧还在打开的文件流会自动调用fclose,不过之后你要想查看fclose所报告的错误,就再没机会了。

函数的语法结构:

#include <stdio.h>
int fclose(FILE *stream);

fflush

fflush函数的作用是把文件流里的所有未写出数据立刻写出。例如,你可以用这个函数来确保在试图读入一个用户响应之前,先向终端送出一个交互提示符。使用这个函数还可以确保在程序继续执行之前重要的数据都已经被写到磁盘上。有时在调试程序时,还可以用它来确定程序是正在写数据而不是被挂起了。注意,调用fclose函数隐含执行了一次flush操作,所以不必在fclose之前调用fflush。

函数的语法结构:

#include <stdio.h>
int fflush(FILE *stream);

fseek

fseek函数是lseek系统调用的文件流等价物,它为文件流的下一次读写操作指定位置。offset和whence参数的含义和取值与前面的lseek系统调用完全一样。但lseek返回的是一个off_t数值,而fseek返回的是一个整数:0表示成功,-1表示失败并设置errno指出错误。

函数的语法结构:

#include <stdio.h>
int fseek(FILE *stream, long int offset, int whence);

fgetc, getc, and getchar

fgetc函数从文件流里取出下一个字节并把它作为一个字符返回。当它到达文件末尾或出现错误时,它返回EOF。你必须通过ferror或feof来区分这两种情况。

函数的语法结构:

#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar();

getc函数的作用和fgetc一样,但它有可能被实现为一个宏,如果是这样,stream参数可能被多次评估以确定其不含有副作用(例如,它不能影响变量)。同时,也不能使用getc的地址作为一个函数指针。

getchar函数相当于getc(stdin),它从标准输入里读取下一个字符。

fputc, putc, and putchar

fputc函数书写一个字符到输出文件流中,它将返回所写入的值,如果失败则返回EOF。

函数的语法结构:

#include <stdio.h>
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);

类似于fgetc和getc之间的关系,putc函数的作用也相当于fputc,但它同样有可能被实现为一个宏。

putchar函数相当于putc(c ,stdout),它把单个字符写到标准输出中。注意,putchar取走和getchar得到的字符都是被当作int而不是char来使用的。这就允许文件尾(EOF)标识取值-1,这是一个超出字符数字编码范围的值。

fgets and gets

fets函数从输入文件流中读取一个字符串。

函数的语法结构:

#include <stdio.h>
char *fgets(char *s, int n, FILE *stream);
char *gets(char *s);

fets函数把读取到的字符写到s所指向的字符串里,直到出现下面这几种情况之一:遇到换行符、已经传输了n-l个字符、或者到达文件末尾。它会把遇到的换行符也传递到接收字符串里去,再加上一个表示结尾的空字节\ 0。一次调用最多只能传输n-1个字符,因为它必须把空字节加上以标示字符串的末尾,且使得整个字符串长度增加至n个字节。

当fgets成功完成时,将返回一个指向字符串s的指针。如果文件流已经到达文件尾,fgets会设置这个文件流的EOF标识并返回一个空指针。如果出现读取错误,fgets将返回一个空指针并设置errno给出错误的类型。

gets函数类似于fgets,除了它是从标准输入读取数据并将所遇到的换行符丢弃,它在接收字符串的尾部加上了一个null字节。

注意:gets对传输字符的个数并没有限制,因此它可能会溢出自己的传输缓冲区。所以我们应该避免使用它,并用fgets来将之替代。许多安全问题都可以追溯到程序中使用了可能造成各种缓冲区溢出的函数,gets就是一个这样的函数,所以千万要小心!

posted on 2008-04-10 12:03  taizi  阅读(581)  评论(0编辑  收藏  举报