Professional C__ - Marc Gregoire [274]
Seeking within an input stream is exactly the same, except that the seekg() method is used:
inStream.seekg(ios_base::beg);
The two-argument versions move to a relative position in the stream. The first argument prescribes how many positions to move and the second argument provides the starting point. To move relative to the beginning of the file, the constant ios_base::beg is used. To move relative to the end of the file, ios_base::end is used. To move relative to the current position, ios_base::cur is used. For example, the following line moves to the second byte from the beginning of the stream. Note that integers are implicitly converted to type ios_base::streampos and ios_base::streamoff:
outStream.seekp(2, ios_base::beg);
The next example moves to the third-to-last byte of an input stream.
inStream.seekg(-3, ios_base::end);
You can also query a stream’s current location using the tell() method which returns an ios_base::streampos that indicates the current position. You can use this result to remember the current marker position before doing a seek() or to query whether you are in a particular location. As with seek(), there are separate versions of tell() for input streams and output streams. Input streams use tellg(), and output streams use tellp().
The following code checks the position of an input stream to determine if it is at the beginning.
ios_base::streampos curPos = inStream.tellg();
if (ios_base::beg == curPos) {
cout << "We're at the beginning." << endl;
}
Following is a sample program that brings it all together. This program writes into a file called test.out and performs the following tests:
1. Outputs the string 12345 to the file.
2. Verifies that the marker is at position 5 in the stream.
3. Moves to position 2 in the output stream.
4. Outputs a 0 in position 2 and closes the output stream.
5. Opens an input stream on the test.out file.
6. Reads the first token as an integer.
7. Confirms that the value is 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;
}
Code snippet from FileStream\FileStream2.cpp
Linking Streams Together
A link can be established between any input and output streams to give them flush-on-access behavior. In other words, when data is requested from an input stream, its linked output stream will automatically flush. This behavior is available to all streams, but is particularly useful for file streams that may be dependent upon each other.
Stream linking is accomplished with the tie() method. To tie an output stream to an input stream, call tie() on the input stream, and pass the address of the output stream. To break the link, pass nullptr.
The following program ties the input stream of one file to the output stream of an entirely different file. You could also tie it to an output stream on the same file, but bidirectional I/O (covered below) is perhaps a more elegant way to read and write the same file simultaneously:
ifstream inFile("input.txt");
ofstream outFile("output.txt");
// Set up a link between inFile and outFile.
inFile.tie(&outFile);
// Output some text to outFile. Normally,