15.3.1 通过seek()和tell()在文件中转移
所有的输入和输出流都有seek()和tell()方法,但是在文件流的上下文之外很少有意义。
seek()方法允许在输入或输出流中移动到任意位置。seek()有好几种形式。输入流中的seek()方法实际上称为seekg()(g表示get的意思),输出流中seek()的版本称为seekp()(p表示put的意思)。您可能想知道为什么同时存在seekg()和seekp()方法,而不是一个seek()方法。原因是有的流既可以输入又可以输出,例如文件流。在这种情况中,流需要记住一个读位置和一个独立的写位置。另外还有本章后面讨论的双向I/O。
seekg()和seekp()有两个重载。一个重载接受一个参数:绝对位置,这个重载定位到这个绝对位置。另一个重载接受一个偏移量和一个位置,这个重载定位到给定位置相对偏移量的位置。位置的类型为ios_base::streampos,偏移量的类型为ios_base::streamoff,这两个类型都以字节计数。预定义的三个位置如表15-3所示。
表 15-3
|
位 置< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> |
说 明 |
|
ios_base::beg |
表示流的开头 |
|
ios_base::end |
表示流的结尾 |
|
ios_base::cur |
表示流的当前位置 |
例如,要定位到输出流的一个绝对位置,可以使用接受一个参数的seekp()版本,如下例所示,这个例子通过ios_base::beg常量定位到流的开头位置:
- outStream.seekp(ios_base::beg);
在输入流中定位完全一样,只不过用的是seekg()方法: - inStream.seekg(ios_base::beg);
接受两个参数的版本定位到流中的相对位置。第一个参数表示要移动的位置数,第二个参数表示起始点。要相对文件起始位置移动,使用ios_base::beg常量。要相对文件末尾位置移动,使用ios_base::end常量。要相对文件当前位置移动,使用ios_base::cur常量。例如,下面这行代码从流起始位置移动到第二个字节。注意,整数被隐式地转换为ios_base::streampos和ios_base::streamoff类型:- outStream.seekp(2, ios_base::beg);
下面这个例子转移到输入流中倒数第3个字节:
- inStream.seekg(-3, ios_base::end);
可以通过tell()方法查询流的当前位置,这个方法返回一个表示当前位置的ios_base::streampos值。利用这个结果,可在进行seek()之前记住当前标记的位置,还可以查询是否在某个特定的位置。和seek()一样,输入流和输出流也有不同版本的tell()。输入流使用的是tellg(),输出流使用的是tellp()。
下面的代码检查输入流的当前位置,并判断是否在起始位置:
- ios_base::streampos curPos = inStream.tellg();
- if (ios_base::beg == curPos) {
- cout << "We're at the beginning." << endl;
- }
下面是一个整合了所有内容的示例程序。这个程序写入一个名为test.out的文件,并且执行以下测试:
(1) 将字符串12345输出至文件。
(2) 验证标记在流中的位置5。
(3) 转移到输出流的位置2。
(4) 在位置2输出0,并关闭输出流。
(5) 在文件test.out文件上打开输入流。
(6) 将第一个标记以整数的形式读入。
(7) 确认这个值是否为12045。
- ofstream fout("test.out");
- if (!fout) {
- cerr << "Error opening test.out for writing" << endl;
- return 1;
- }
- // 1. Output the string "12345".
- fout << "12345";
- // 2. Verify that the marker is at position 5.
- ios_base::streampos curPos = fout.tellp();
- if (5 == curPos) {
- cout << "Test passed: Currently at position 5" << endl;
- } else {
- cout << "Test failed: Not at position 5" << endl;
- }
- // 3. Move to position 2 in the stream.
- fout.seekp(2, ios_base::beg);
- // 4. Output a 0 in position 2 and close the stream.
- fout << 0;
- fout.close();
- // 5. Open an input stream on test.out.
- ifstream fin("test.out");
- if (!fin) {
- cerr << "Error opening test.out for reading" << endl;
- return 1;
- }
- // 6. Read the first token as an integer.
- int testVal;
- fin >> testVal;
- // 7. Confirm that the value is 12045.
- const int expected = 12045;
- if (testVal == expected) {
- cout << "Test passed: Value is " << expected << endl;
- } else {
- cout << "Test failed: Value is not " << expected
- << " (it was " << testVal << ")" << endl;
- }
-
- 代码取自FileStream\FileStream2.cpp
-