【问题标题】:ifstream::seekg giving wrong resultsifstream::seekg 给出错误的结果
【发布时间】:2017-05-31 17:54:29
【问题描述】:

我正在使用 ifstream 来熟悉它。我正在尝试使用 seekg 来判断文件的位置,但它给了我错误的结果。

这个想法是:

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

原始文件是这样的(windows格式):

文件.txt

aA
bB
cC
dD
eE
fF

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

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

但是,对于这个文件:

文件.txt

aAbBcCdDeEfF

我得到了这些结果

position: 0
got: a
position: 1
got: A
position: 2

这是我使用的代码:

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

这里分别是两个文本文件的两个十六进制编辑器视图:

原创 修改

我预计两者都会分别产生结果 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?

可能的解释(在下面测试 Holt 的答案)

此代码中的 f.tellg 求助于 f.rdbuf()-&gt;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。总的来说,这两个问题有不同的上下文,知道该问题的答案并不能回答这个问题。

【问题讨论】:

  • 在十六进制编辑器中比较文件。也许在文件的开头有一个 BOM 或一些奇怪的看不见的废话,操作系统会为您读取并跳过(除非您以二进制模式打开文件)。
  • 在底部添加了十六进制视图。前 2 个字符是相同的,所以我看不出它会如何影响 seekg。
  • 您使用的是什么操作系统和编译器?请提供确切的版本。
  • @Dmitry 当文件以文本模式打开时,tellg() 的返回值是未指定的(它只是用作seekg() 的参数)。

标签: c++ ifstream seekg


【解决方案1】:

tellg() 返回的值没有任何“错误”结果:当文件以文本模式打开时,返回值是未指定(即它除了可以用作seekg()的输入之外没有任何意义。

基本上,在basic_fstream 上调用tellg() 会退回到std::ftell1 函数,该函数表示(C 标准,§7.21.9.4 [文件定位函数],强调是我的):

long int ftell(FILE *stream);

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

1tellg() 回退到rdbuf()-&gt;pubseekoff(0, std::ios_base::cur, std::ios_base::in),后者回退到basic_filebuf::seekoff(0, std::ios_base::cur, std::ios_base::in),然后又回退到std::ftell()

【讨论】:

  • 我直接去 pubseekoff 测试了你的答案,它确实给出了相同的错误值,但前提是 ifstream 的构造函数没有给出ios_base::in | ios_base::binary。仍然好奇幕后发生了什么来产生这 1,6,7 个结果,而不是 0,1,2。
  • @Dmitry 这高度依赖于操作系统(和编译器) - 特别是在 Windows 上,您可以在文本模式下进行一些翻译,例如为'\n'。我用你的文本文件尝试了你的代码,我什至没有得到和你一样的结果(我得到了 7 8 和 2 3)。这可能是因为我在每个文件的末尾添加了一个额外的'\n',这将证实'\n'的翻译对Windows的影响。
猜你喜欢
  • 2014-09-16
  • 2013-04-28
  • 2011-11-15
  • 2019-02-06
  • 2014-01-30
  • 2018-08-01
  • 2016-08-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多