1

我正在玩 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()->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() 函数的区别给出错误的文件大小?. 该问题默认设置了 ios::binary ,并使用 seek; 这里的这个问题有 ios::binary 和没有,并且不使用 seek。总的来说,这两个问题有不同的背景,知道该问题的答案并不能回答这个问题。

4

1 回答 1

6

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

基本上,对tellg()on a的调用basic_fstream回退到1函数,它说(C 标准,§7.21.9.4 [文件定位函数],重点是我的):std::ftell

long int ftell(FILE *stream);

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

1 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()

于 2017-05-31T18:18:19.323 回答