15.7 关闭流
流使用函数fclose关闭的,它的原型如下:
int fclose( FILE *f );
对于输出流,fclose函数在文件关闭之前刷新缓冲区。如果它执行成功,fclse返回值零,否则返回EOF。
程序15.1把它的命令行参数解释为一列文件名。它打开每个文件并逐个对它们进行处理。如果有任何一个文件无法打开,它就打开一条包含该文件名的错误信息。然后程序继续处理列表中的下一个文件名。退出状态(exit status)取决于是否有错误发生。
前文提到,任何有可能失败的操作都应该进行检查,确实它是否成功执行。这个程序对fclose函数的返回值进行了检查,看看是否有什么地方出现了问题。许多程序员懒得执行这个测试,它们争辩说关闭文件没理由失败。更何况,此时对这个文件的操作已经结束,即使fclose函数失败也并无大碍。然而,这并不完全正确。
/*
**处理每个文件名出现于命令行的文件。
*/
#include<stdlib.h>
#include<stdio.h>
int main( int ac, char **av ){
int exit_status = EXIT_SUCCESS;
FILE *input;
/*
**当还有更多的文件名时...
*/
while( *++av != NULL ){
/*
**试图打开这个文件。
*/
input = fopen( *av, "r" );
if( input == NULL ){
perror( *av );
exit_status = EXIT_FAILURE;
continue;
}
/*
**在这里处理这个文件...
*/
/*
**关闭文件(期望这里不会发生什么错误)。
*/
if( fclose( input ) != 0 ){
perror( "fclose");
exit( EXIT_FAILURE );
}
}
return exit_status;
}
程序15.1 打开和关闭文件 open_cls.c
/*
**处理每个文件名出现于命令行的文件。
*/
#include<stdlib.h>
#include<stdio.h>
int main( int ac, char **av ){
int exit_status = EXIT_SUCCESS;
FILE *input;
int counter;
counter = 0;
/*
**当还有更多的文件名时...
*/
while( *++av != NULL ){
/*
**试图打开这个文件。
*/
input = fopen( *av, "r" );
if( input == NULL ){
perror( *av );
exit_status = EXIT_FAILURE;
continue;
} else{
counter++;
}
/*
**在这里处理这个文件...
*/
/*
**关闭文件(期望这里不会发生什么错误)。
*/
if( fclose( input ) != 0 ){
perror( "fclose");
exit( EXIT_FAILURE );
}
}
printf( "ac = %d, counter = %d\n", ac, counter );
if( counter == ac - 1 ){
printf( "all files are read successfully.\n" );
} else{
printf( "not all files are read successfully.\n" );
}
return exit_status;
}
/* 输出:
*/
input变量会因为fopen和fclose之前的一个程序bug而发生修改。这个bug无疑将导致程序失败。在那些并不检查fopen函数返回值的程序中,input的值甚至有可能是NULL。在任何一种情况下,fclose都将失败,而且程序很可能在fclose被调用之前很早便已终止。那么是否应该对fclose(或任何其他操作)进行错误检查呢?在做出决定之前,先问自己两个问题。
1.如果操作成功应该执行什么?
2.如果操作失败应该执行什么?
如果这两个问题的答案是不同的,那么就应该进行错误检查。只有当这两个问题的答案是相同时,跳过错误检查才是合理的。