C++/I/O
Expert: Ralph McArdell - 10/19/2007
Questionhello
after executing the following code
ifstream infile;
...
while(!infile.eof()){
//read each character inside file
}
how can i go back to the beginning of the file?
(i want to read the first character of the file)
thanks
AnswerI suggest you try:
infile.seekg(0, std::ios::beg);
I am assuming ISO standard C++ IOStreams and not any form of pre-standard IOStreams (sometimes called traditional IOStreams) - that is you included the standard header <fstream> (note: no .h extension) not something like <fstream.h>, and have used a using directive for namespace std:
using namespace std;
Or a using declaration for std::ifstream:
using std::ifstream;
If you are using an old, pre-standard version of IOStreams, then the solution could be similar - maybe without the std:: namespace qualification, or you may have to obtain a pointer to the file buffer (of type filebuf) by calling rdbuf and call its seekoff member:
// Possible use for pre-standard IOStreams
infile.rdbuf()->seekoff(0, ios::beg, ios::in);
The example above would seem correct for a pre-standard IOStreams implementation shipped with a Watcom compiler - if I have read the manual correctly. I used this as an example as I have the manual available. However as I no longer use pre-standard compilers I cannot check it is correct, and have forgotten much detail from that time - sorry!
In either case the file read position is positioned 0 bytes from the beginning of the file - this is what the 0 and (std::)ios::beg parameter values mean.
Other interpretations of the position value other than from the beginning of the file can be used by specifying different values for the second parameter. To have the position value be used relative to the end of the file use (std::)ios::end (which implies pos should be <= 0). To have the position value be interpreted relative to the current position use (std::)ios::cur.
Note: I am placing the qualification of the std:: namespace in () as it may not be required, however strictly it is part of the fully qualified names of ios::beg, ios::end, and ios::cur for standard C++ IOStream implementations. That is they are std::ios::beg, std::ios::end and std::ios::cur.
For standard C++ IOStream implementations there are separate file positions for reading and writing (or getting and putting). This is the reason the seekg operation has a g on the end - seek get position. This implies there would be a seek put position for writing and indeed there is: std::fstream objects (including std::ifstream and std::ofstream) have a seekp member function, for example:
outfile.seekp(0, std::ios::end); // position to end of file
To go with the operations to modify the file read and write positions are operations to return their current values. These are the tell member functions tellg and tellp:
std::streampos read_pos = infile.tellg();
std::streampos write_pos = outfile.tellp();
These position values can then be used with seekp and seekg.
For the record I should point out that the example using traditional IOStreams affects both the read and write position. The third argument to the traditional filebuf::seekoff function should specify which position (read or write or both) is affected but the documentation for this implementation states that the get and put areas are tied together so there is only one file position that covers both read and write, hence the third parameter is ignored.
Also for the record I should point out that the standard C++ IOStreams are similar to the older IOStreams library, and so we can also change the file read and write position using stream (file) buffers in standard C++ IOStreams. In fact it is a stream's associated stream buffer that does all the real work and different buffer types allow streams to work with different storage devices - such as strings and files. The details for using a std::filebuf are a little different to the traditional filebuf. The member function rdbuf is still used to access the stream object associated with a stream, but the operations on a standard filebuf are a little different:
// Standard C++ IOStream file positioning
// using std::filebuf steam buffer:
// Position to the 0th absolute file position
// for both read and write
infile.rdbuf()->pubseekpos(0);
// Position to the 0th absolute file position
// for both read only
infile.rdbuf()->pubseekpos(0, std::ios_base::in);
// Position to the 0th file position from the beginning of file
// for both read and write
infile.rdbuf()->pubseekoff(0, std::ios::beg);
// Position to the 0th file position from the beginning of file
// for both read only
infile.rdbuf()->pubseekoff(0, std::ios::beg, std::ios_base::in);
Note: rdbuf returns a pointer to the stream's associated stream buffer. As it is a pointer it could possibly be a null pointer value (although it should not be if the stream is functioning correctly!). I have not bothered to check that rdbuf returns a valid pointer in my example code for brevity.
Also a std::filebuf _does_ have separate get and put areas and these may not be tied together and only one area may be active at a time. I am not going to go into the gory details here - as I would first have to revise them myself and the details of just how a filebuf object works with input, output and switching between the two is quite complex for a Q and A forum like this, and you really do have to have your brain in gear to follow it through!! (my IOStream text here - "Standard C++ IOStreams and Locales" by Langer and Kreft - takes over 10 pages with 15 diagrams to describe the behaviour of an example implementation of filebuf)
In short then I hope you are using a standard C++ IOStreams implementation and therefore do not have to bother with filebufs, as this is obviously the most convenient interface to use (which I suppose is why it was included!) - if you are like me you probably think that dropping down to the stream buffer level just to do something so simple is a bit over the top!
Finally I should note that you can of course re-position the file pointer to the start of the file by simply closing and re-opening the file for reading:
infile.close();
infile.open( filepathname );
if ( infile.is_open() )
{
// proceed...
}
else
{
// handle unable to open file error
}
Hope this helps.