2017-05-31 147 views
1

我在玩ifstream来熟悉它。我正在尝试使用seekg来告诉文件的位置,但它给了我错误的结果。ifstream :: seekg给出了错误的结果

的想法是:

  1. 打开的文件的文件
  2. 打印位置
  3. 从文件中读取一个字符
  4. 文件
  5. 打印位置读取一个字符从文件
  6. 文件的打印位置
  7. 关闭文件。

原始文件看起来像这样(Windows格式):

file.txt的

aA 
bB 
cC 
dD 
eE 
fF 

运行我的代码,我得到的结果:

position: 0 
got: a 
position: 6 
got: A 
position: 7 

然而,对于此文件:

file.txt的

aAbBcCdDeEfF 

我得到这些结果

​​

这里是我使用的代码:

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; 
} 

这里是th两个文本文件分别Ë两个十六进制编辑观点:

enter image description here 修改enter image description here

我希望既能产生结果。0,1,2分别,然而这不是原始实验的情况。

有人可以解释这里发生了什么吗?

问题

  1. 我应该怎么做才能得到正确的文件中的位置?

答:使用ifstream("file.txt", ios_base::in | ios_base::binary)构造了ifstream("file.txt")构造。

  1. 是什么导致f.tellg默认给出这些奇怪的值0,6,7而不是预期的1,2,3?

可能的解释(测试由以下霍尔特答案)在此代码度假村

f.tellg到f.rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in)其是负责产生值0,6,7(但只有当ios_base::binary是不在施工/开放时指定)。

#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; 
} 

注意传递ios::in | ios::binary作为第二个参数的构造函数ifstream的使这两个文件像预期的那样,但我想也知道是什么引起的默认行为给这些奇怪所以tellg值。

备注区别于tellg() function give wrong size of file?。这个问题有默认的ios :: binary设置,并使用seek;这里的这个问题既有ios :: binary也没有,并且不使用seek。总的来说,这两个问题有不同的背景,并且知道这个问题的答案不能回答这个问题。

+0

比较十六进制编辑器中的文件。也许在文件开始时有一个BOM或一些奇怪的看不见的废话,OS会为你读取和跳过(除非你以二进制模式打开文件)。 – tambre

+0

在底部添加了十六进制视图。前两个字符是相同的,所以我不知道它会如何影响seekg。 – Dmitry

+0

你在使用什么操作系统和编译器?请包括确切的版本。 – tambre

回答

5

没有什么作为由tellg()返回的值是“错误”的结果是:如果在文件中文本模式被打开,返回值是不确定(即它有不同之处在于它可以用于任何意义作为seekg()的输入)。

基本上,在basic_fstreamtellg()呼叫回落到std::ftell 功能,它说(C标准,§ 7.21.9.4 [文件定位功能],强调的是矿):

long int ftell(FILE *stream);

ftell函数获取stream指向的流的文件位置指示符的当前值。 [...]对于文本流,其文件位置指示器包含未指定的信息fseek函数可用于将 流的文件位置指示符返回到其在调用ftell时的位置;两个这样的返回值之间的差异是不一定是写或读的字符数量的有意义的度量。

tellg()回落到rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::in),其回退到basic_filebuf::seekoff(0, std::ios_base::cur, std::ios_base::in)然后回落到std::ftell()

+0

我通过直接去pubseekoff来测试你的答案,它确实给出了相同的错误值,但只有ifstream的构造函数没有被赋予'ios_base :: in |的ios_base :: binary'。仍然好奇背后幕后发生这些1,6,7结果而不是0,1,2。 – Dmitry

+0

@Dmitry这是高度依赖操作系统(和编译器) - 特别是在Windows上,你有一些在文本模式下的翻译,例如为''\ n''。我用你的文本文件尝试了你的代码,我甚至没有得到和你一样的结果(我得到了7 8和2 3)。这可能是因为我在每个文件的末尾添加了一个额外的'\ n',这将确认在Windows上转换'\ n''的影响。 – Holt