Reputation: 5213
I am playing with ifstream to familiarize myself with it. I am trying to use seekg to tell the position of the file, but it is giving me wrong results.
The idea is to:
The original file looks like this(windows format):
file.txt
aA
bB
cC
dD
eE
fF
running my code, I get the results:
position: 0
got: a
position: 6
got: A
position: 7
However, for this file:
file.txt
aAbBcCdDeEfF
I get these results
position: 0
got: a
position: 1
got: A
position: 2
Here is the code I used:
test.cpp(mingw/gcc5.3)
#include <fstream>
#include <iostream>
using namespace std;
static char s[10];
int main(int argc, char **argv)
{
ifstream f("file.txt");
cout << "position: " << f.tellg() << "\n";
f.read(s, 1);
cout << "got: " << s << "\n";
cout << "position: " << f.tellg() << "\n";
f.read(s, 1);
cout << "got: " << s << "\n";
cout << "position: " << f.tellg() << "\n";
f.close();
return 0;
}
Here are the two hex editor views of the two text files respectively:
I expected both to yield the results 0, 1, 2 respectively, however this was not the case for the original experiment.
Can somebody explain what is happening here?
Questions:
Answer: use
ifstream("file.txt", ios_base::in | ios_base::binary)
constructor overifstream("file.txt")
constructor.
possible explanation(testing an answer by Holt below)
f.tellg in this code resorts to f.rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in)
which is responsible for producing the values 0, 6, 7(but only if ios_base::binary
is not specified at construction/open).
#include <fstream>
#include <iostream>
using namespace std;
static char s[10];
int main(int argc, char **argv)
{
ifstream f("file.txt");
cout << "position: " << f.rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in) << "\n";
f.read(s, 1);
cout << "got: " << s << "\n";
cout << "position: " << f.rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in) << "\n";
f.read(s, 1);
cout << "got: " << s << "\n";
cout << "position: " << f.rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in) << "\n";
f.close();
return 0;
}
Note passing ios::in | ios::binary
as the second argument to the ifstream constructor makes both files behave as expected, but I would like to also know what's causing the default behavior to give these strange tellg values.
Note difference from tellg() function give wrong size of file?. That question has ios::binary set by default, and uses seek; this question here has both ios::binary and without, and does not use seek. Overall, the two questions have different contexts, and knowing the answer to that question does not answer this one.
Upvotes: 1
Views: 1507
Reputation: 37606
There is nothing as a "wrong" result for a value returned by tellg()
: when the file is opened in text mode, the return value is unspecified (i.e. it has no meaning except that it can be used as input for seekg()
).
Basically, a call to tellg()
on a basic_fstream
falls back to the std::ftell
1 function, which says (C standard, §7.21.9.4 [File positioning functions], emphasis is mine):
long int ftell(FILE *stream);
The
ftell
function obtains the current value of the file position indicator for the stream pointed to bystream
. [...] For a text stream, its file position indicator contains unspecified information, usable by thefseek
function for returning the file position indicator for the stream to its position at the time of theftell
call; the difference between two such return values is not necessarily a meaningful measure of the number of characters written or read.
1 tellg()
falls back to rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::in)
, which falls back to basic_filebuf::seekoff(0, std::ios_base::cur, std::ios_base::in)
which then falls back to std::ftell()
.
Upvotes: 6