15.6 打开流
fopen函数打开一个特定的文件,并把一个流和这个文件相关联。它的原型如下所示:
FILE *fopen( char const *name, char const *mode );
name是希望打开的文件或设备的名字。创建文件名的规则在不同的系统中可能各不相同,所以fopen把文件名作为一个字符串而不是作为路径名、驱动器字母、文件扩展名等并准备一个参数。这个参数指定要打开的文件---FILE*变量的名字供程序用来保存fopen的返回值,它并不影响哪个文件被打开。mode(模式)参数提示流是用于只读、只写还是既读又写,以及它是文本流还是二进
制流。表15.3列出了一些常用的模式。
表16.8 常用模式
读取 写入 添加
文本 "r" "w" "a"
二进制 "rb" "wb" "ab"
mode以r、w或a开头,分别表示打开的流用于读取、写入还是添加。如果一个打开的文件是用于读取,那么它必须原先已经存在。但是,如果一个打开的文件是用于写入,如果它原先已经存在,那么它原来的内容就会删除。如果它原先不存在,就创建一个新文件。如果一个打开的用于添加的文件原先并不存在,那么它将被创建。如果它原先已经存在,则原先的内容并不会被删除。无论在哪一种情况下,数据只能从文件的尾部写入。
在mode中添加“a+”表示打开的文件用于更新,并且流既允许读也允许写。但是,如果已经从该文件读入了一些数据,那么在开始向它写入数据之前,必须调用其中一个文件定位函数(fseek、fsetpos、rewind)。在向文件写入一些数据之后,如果又想从该文件读取一些数据,则首先必须调用fflush函数或者文件定位函数之一。
如果fopen函数执行成功,它将返回一个指向FILE结构的指针,该结构代表这个新创建的流。如果函数执行失败,它就返回一个NULL指针,error会提示问题的性质。
警告:
应该始终检查fopen函数的返回值!如果函数失败,它会返回一个NULL值。如果程序不检查错误,这个NULL指针就会传给后续的I/O函数。它们将对这个指针执行间接访问,并将失败。下面的例子说明了fopen函数的用法:
FILE *input;
input = fopen( "data3", "r" );
if( input == NULL ){
perror( "data3" );
exit( EXIT_FAILURE );
}
首先,fopen函数被调用。这个被打开的文件名为data3,用于读取。这个步骤之后就是对返回值进行检查,确定文件打开是否成功,这非常重要。如果失败,错误就被报告给用户,程序也将终止。调用perror所产生的确切输出结果在不同的操作系统中可能各不相同,但它大致应该像下面这个样子。
data3: No such file or directory
/*
** 打开流。
*/
#include <stdio.h>
#include <stdlib.h>
int main( void ){
FILE *input;
/* here, data3.txt file doesn't exist, data.txt file exists. You need to creat data.txt file by yourself.*/
input = fopen( "data.txt", "r" );
if( input == NULL ){
perror( "data.txt" );
exit( EXIT_FAILURE );
} else{
printf( "open data.txt successfully.\n" );
}
input = fopen( "data3.txt", "r" );
if( input == NULL ){
perror( "data3.txt" );
exit( EXIT_FAILURE );
} else{
printf( "open data3.txt successfully.\n" );
}
return EXIT_SUCCESS;
}
/* 输出:

*/
这种类型的信息清楚地向用户报告有一个地方出了差错,并很好地提示了问题的性质。在那些读取文件名或者从命令行接受文件名的程序中,报告这些错误尤其重要。当用户输入一个文件名时,存在出错的可能性。显然,描述性的错误信息能够帮助用户判断哪里错了以及如何修正它。
freopen函数用于打开(或重新打开)一个特定的文件流。它的原型如下:
FILE *freopen( char const *filename, char const *mode, FILE *stream );
最后1个参数就是需要打开的流。它可能是一个先前从fopen函数返回的流,也可能是标准流stdin、stdout或stderr。
这个函数首先试图关闭这个流,然后用指定的文件和模式重新打开这个流。如果打开失败,函数返回一个NULL值。如果打开成功,函数就返回它的第3个参数值。
/*
** freopen。
*/
#include <stdio.h>
#include <stdlib.h>
int main( void ){
FILE *input;
/* here, data3.txt file doesn't exist, data.txt file exists. You need to creat data.txt file by yourself.*/
input = fopen( "data.txt", "r" );
if( input == NULL ){
perror( "data.txt" );
exit( EXIT_FAILURE );
} else{
printf( "open data.txt successfully.\n" );
}
input = freopen( "data.txt", "w", input );
if( input == NULL ){
perror( "data.txt" );
exit( EXIT_FAILURE );
} else{
printf( "open data.txt successfully.\n" );
printf( "hello, wordl!" );
}
return EXIT_SUCCESS;
}
/* 输出:

*/