Iostream support for file positioning operations depends on the character encoding of a particular stream. For fixed-width encodings, such as ASCII or UNICODE, the file stream classes allow a full set of positioning operations comparable to those offered by `C' stdio. The options for variable-width and state-dependent encodings, such as JIS, are limited. For these more complex encodings, the only allowed positioning operations are 'seek to beginning', 'seek to end', or 'seek to a previously known location'. The last option requires that you arrive at and then store a particular position before a seek can be performed. Attempting to seek to an arbitrary offset on a stream with variable-width or state-dependent character encodings has an undefined effect on the file position. Here's an example of the correct way to seek to a position in any file stream, regardless of encoding:
int main(int argc, char argv[])
{
std::ofstream fs("foo.out");
fs << "Anyone"; //1
std::ofstream::pos_type p = fs.tellp(); //2
fs << " remember J.P. Patches?"; //3
fs.seekp(p); //4
}
This is the only possible method for seeking to an arbitrary position--that is, a position other than beginning or end of file--in a stream with variable or state-dependent character encoding. Of course, the method also works with fixed-width encodings.
The example above shows one use of two of the output file positioning functions, tellp() and a version of seekp(). An ofstream also has another version of the seekp() function that allows a seek to an arbitrary offset in much the same way that the `C' stdio fseek() function works. This function can be used to seek to the beginning or end of any ofstream, or anywhere else in an ofstream with a fixed-width character encoding. For instance:
std::ofstream fs("foo.out");
fs << "Anyone remember J.P. Patches?";
fs.seekp(-2, std::ios_base::cur); //1
fs.seekp(0, std::ios_base::beg); //2
The first parameter of this function is a value of std::ofstream::off_type, and the second is one of three constants indicating starting position for the seek. These three values correspond to the three possible seek types available with the `C' stdio function fseek(). They are defined in the base class std::ios_base. The table below summarizes the three different kinds of seeks possible with this version of seekp():
seek relative to beginning of file
ios_base::beg
SEEK_SET
seek relative to end of file
ios_base::end
SEEK_END
seek relative to current position
ios_base::cur
SEEK_CUR
As in the example, passing 0 as the offset with std::ios_base::beg as the seek type seeks to the beginning of the file. Likewise, using 0 with std::ios_base::end seeks to the end of the file. Since the function returns the current position after the seek operation, passing 0 along with std::ios_base::cur gets you the current file position without moving it. This is equivalent to calling the tellp() member function.
ifstream provides the same set of functions but with slightly different names: tellg() instead of tellp(), and seekg(...) instead of seekp(...). The reason for this specialized naming scheme can be seen in the fstream class, which provides both sets of functions so that the input and output streams can be manipulated separately.
If you look at the iostream class definitions, you notice that the seek functions are not defined in these classes. Instead, they are inherited from a base class template: basic_ostream for tellp() and seekp(), and basic_istream for tellg() and seekg(). These functions then call (indirectly, through their public interface) virtual functions in the stream buffer, where seeking is actually implemented. Seek functions for ofstream, ifstream, and fstream actually call pubseekoff() and pubseekpos() in filebuf. The code looks like this:
template<class CharT, class Traits>
basic_ostream<CharT, Traits>&
basic_ostream<CharT, Traits>::seekp (pos_type pos)
{
if (!this->fail () &&
-1 == this->rdbuf()->pubseekpos (pos,
ios_base::out)) this->setstate (ios_base::failbit);
return *this;
}
Calling virtual functions in the stream buffer maintains the fundamental separation of buffer manipulation and I/O from string formatting. While it's not necessary to know this in order to use file seek operations, it is important if you ever need to subclass a stream buffer.