C++ primer plus 第17 章 输入、输出和文件:文件输入和输出01
17.4.2 流状态检查和is_open()
17.4.3 打开多个文件
17.4.4命令行处理技术
程序清单17.17 count.cpp
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
17.4.2 流状态检查和is open()
C++文件流类从iosbase 类那里继承了一个流状态成员。正如前面指出的,该成员存储了指出流状态的信息:一切顺利、已到达文件尾、I/0 操作失败等。如果一切顺利,则流状态为零(没有消息就是好消息)。其他状态都是通过将特定位设置为1来记录的。文件流类还继承了iosbase 类中报告流状态的方法,表17.4对这些方法进行了总结。可以通过检查流状态来判断最后一个流操作是否成功。对于文件流,这包括检查试图打开文件时是否成功。例如,试图打开一个不存在的文件进行输入时,将设置ilbit位,因此可以这样进行检查:
fin.open(argv[file]):
if (fin.fail())// open attempt failed
{
...
}
由于 ifstrcam 对象和 istrcam 对象一样,被放在需要 bool类型的地方时,将被转换为 bool值,因此您也可以这样做:
fin.open(argvlfile]);
if (!fin)//open attempt failed
{
...
}
。
然而,较新的C++实现提供了一种更好的检查文件是否被打开的方法–is_open()方法:
if(!fin.is open())//open attempt failed
{
...
}
这种方式之所以更好,是因为它能够检测出其他方式不能检测出的微妙问题,接下来的“警告”将讨论这一点。
警告:以前,检查文件是否成功打开的常见方式如下:
if(fin.fail())...// failed to open
if(!fin.good())...// failed to open
if (!fin)...
//failed to openfin 对象被用于测试条件中时,如果 fin.good()为fàlsc,将被转换为falsc;否则将被转换为 tnue。因此上面三种方式等价。然而,这些测试无法检测到这样一种情形:试图以不合适的文件模式(参见本章后面的“文件模式”一节)打开文件时失败。方法is_open( )能够检测到这种错误以及 good()能够检测到的错误然而,老式C++实现没有is_open()。
17.4.3 打开多个文件
程序可能需要打开多个文件。打开多个文件的策略取决于它们将被如何使用。如果需要同时打开两个文件,则必须为每个文件创建一个流。例如,将两个排序后的文件拼接成第三个文件的程序,需要为两个输入文件创建两个 ifstream 对象,并为输出文件创建一个 ofstream 对象。可以同时打开的文件数取决于操
作系统。然而,可能要依次处理一组文件。例如,可能要计算某个名称在10个文件中出现的次数。在这种情况下,可以打开一个流,并将它依次关联到各个文件。这在节省计算机资源方面,比为每个文件打开一个流的效率高。使用这种方法,首先需要声明一个istream对象(不对它进行初始化),然后使用 open( )方法将这个流与文件关联起来。例如,下面是依次读取两个文件的代码:
ifstream fin;//ereate stream using default construetor
fin.open("fat.txt");//associate stream with fat.txt file
...
fin.close();//terminate association with fat.txt
fin.clear();//reset fin (may not be needed)
fin.open("rat.txt”);//associate stream with rat.txt file
...// do stuff
...
fin.close();
稍后将介绍一个例子,但先来看这样一种将一系列文件输入给程序的技术,即让程序能够使用循环来处理文件。
17.4.4命令行处理技术
文件处理程序通常使用命令行参数来指定文件。命令行参数是用户在输入命令时,在命令行中输入的参数。例如,要在UNIX或Linux系统中计算文件包含的字数,可以在命令行提示符下输入下面的命令:
wc reportl report2 report3其中,wc是程序名,report1、report2和report3 是作为命令行参数传递给程序的文件名。C++有一种让在命令行环境中运行的程序能够访问命令行参数的机制,方法是使用下面的main()函数:
int main(int argc,char *argv])
argc为命令行中的参数个数,其中包括命令名本身。argv变量为一个指针,它指向一个指向char 的指针。这过于抽象,但可以将 argv看作一个指针数组,其中的指针指向命令行参数,argv[0]是一个指针,指向存储第一个命令行参数的字符串的第一个字符,依此类推。也就是说,argv[0]是命令行中的第一个字符串,依此类推。例如,假设有下面的命令行:
we reportl report2 report3
则argc为4,argv[0]为wc,argv[1]为reportl,依此类推。下面的循环将把每个命令行参数分别打印在单独一行上:
for (int i=l;i < argc; i++)
cout << argvli]<< endl;
以i-1开头将只打印命令行参数:以i=0开头将同时打印命令名。当然,命令行参数与命令行操作系统(如 Windows命令提示符模式、UNIX和Linux)紧密相关。其他程序也可能允许使用命令行参数。
很多 WindowsIDE(集成开发环境)都有一个提供命令行参数的选项。通常,必须选择一系列菜单,才能打开一个可以输入命令行参数的对话框。具体的步骤随厂商和升级版本而异,因此请查看文档。
很多 WindowsIDE都可以生成可执行文件,这些文件能够在 Windows 命令提示符模式下运行。
程序清单 17.17结合使用命令行技术和文件流技术,来计算命令行上列出的文件包含的字符数。
程序清单17.17 count.cpp
// count.cpp -- counting characters in a list of files
#include <iostream>
#include <fstream>
#include <cstdlib> // or stdlib.h
int main(int argc, char * argv[])
{
using namespace std;
if (argc == 1) // quit if no arguments
{
cerr << "Usage: " << argv[0] << " filename[s]\n";
exit(EXIT_FAILURE);
}
ifstream fin; // open stream
long count;
long total = 0;
char ch;
for (int file = 1; file < argc; file++)
{
fin.open(argv[file]); // connect stream to argv[file]
if (!fin.is_open())
{
cerr << "Could not open " << argv[file] << endl;
fin.clear();
continue;
}
count = 0;
while (fin.get(ch))
count++;
cout << count << " characters in " << argv[file] << endl;
total += count;
fin.clear(); // needed for some implementations
fin.close(); // disconnect file
}
cout << total << " characters in all files\n";
return 0;
}