15.4 双向I/O
目前,本章已经讨论了输入和输出流,讨论的时候把这两个类当做独立但又关联的类。事实上,有一种流可以同时执行输入和输出。双向流可以同时以输入流和输出流的方式操作。
双向流是iostream的子类,而iostream是istream和ostream的子类,因此这是一个多重继承的实例。跟直觉一样,双向流同时支持>>运算符和<<运算符,还支持输入流和输出流的方法。
fstream类提供了双向文件流。fstream特别适合于需要替换文件中数据的应用程序,因为可以通过读取文件找到正确的位置,然后立即切换为写入文件。例如,假设一个程序保存一个ID号和电话号码之间的映射列表。这个程序可能使用以下格式的数据文件:
- 123 408-555-0394
- 124 415-555-3422
- 164 585-555-3490
- 100 650-555-3434
一个合理的方案是当这个程序打开文件的时候读取整个数据文件,然后在程序结束的时候,将所有的变化重新写入这个文件。然而,如果数据集巨大,可能无法把所有数据都保存在内存中。如果使用iostream,则不需要这样。您可以轻松扫描文件找到记录,然后以追加模式打开输出文件来添加新记录。如果要修改已有记录,可以使用双向流,例如下面的函数替换指定ID的电话号码:- bool changeNumberForID(const string& inFileName, int inID,
- const string& inNewNumber)
- {
- fstream ioData(inFileName.c_str());
- if (!ioData) {
- cerr << "Error while opening file " << inFileName << endl;
- return false;
- }
- // Loop until the end of file
- while (ioData.good()) {
- int id;
- string number;
- // Read the next ID.
- ioData >> id;
- // Check to see if the current record is the one being changed.
- if (id == inID) {
- // Seek to the current read position
- ioData.seekp(ioData.tellg());
- // Output a space, then the new number.
- ioData << " " << inNewNumber;
- break;
- }
- // Read the current number to advance the stream.
- ioData >> number;
- }
- return true;
- }
-
- 代码取自Bidirectional\Bidirectional.cpp
当然,只有在数据大小固定的时候这种方法才能正常工作。当以上程序从读取切换到写入的时候,输出数据会改写文件中的其他数据。为了保持文件的格式,并且避免写入下一条记录,数据必须相同大小。
还可以通过stringstream类双向访问字符串流。
双向流用不同的指针保存读位置和写位置。在读取和写入之间切换的时候,需要定位到正确的位置。