tellg()仅为小文件返回-1

时间:2018-01-05 01:13:43

标签: c++ c++11 fstream

我遇到了一个特殊的问题。假设我正在读这样一个文件:

std::ifstream in("file.txt", std::ios::binary);
std::string text;
in.seekg(0, std::ios::end);
text.resize(in.tellg());
in.seekg(0, std::ios::beg);
in.read(&text[0], text.size());

当文件包含少于4个字符(即"ab""abc")时会出现问题,但在其他情况下会按预期工作,即"abcd"或更大。

为什么tellg在这种情况下返回-1(最终导致我的字符串抛出std::length_error)?

其他信息:

我正在使用MSVC 15.5.3(如果不是最新的,更现代的一个)。也用GCC 5.1重现。

等效的C风格不会发生此错误:

FILE* f = fopen("text.txt", "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);

修改

failbit在第一次调用seekg之前设置,这意味着打开文件失败了?为什么小于3字节的文件就是这种情况......

1 个答案:

答案 0 :(得分:3)

在发表一些评论之后,很明显ifstream构造函数本身在某种程度上失败了,因为failbit在<{em> seekg调用之前被设置为

由于几乎所有 I / O操作在继续之前首先构造一个哨兵对象,这就是你的操作失败的原因。

所以我有一些建议。

首先,将完整路径名用于您的文件,以确保您无法在其他目录中运行它,而不是输入文件所在的目录。< / p>

其次,尝试以下完整的程序,该程序在g ++ 5.4 (a)下运行,看它是否表现出同样的问题(你的代码,虽然是指示性的,但并不是真的完成)。

#include <iostream>
#include <fstream>

int main() {
    std::ifstream in("/full/path/to/file.txt", std::ios::binary);
    std::cout << "after open, good=" << in.good() << ", bad=" << in.bad()
        << ", fail=" << in.fail() << ", eof=" << in.eof() << std::endl;

    std::cout << "seekg returns " << in.seekg(0, std::ios::end) << std::endl;
    std::cout << "after seek, good=" << in.good() << ", bad=" << in.bad()
        << ", fail=" << in.fail() << ", eof=" << in.eof() << std::endl;

    std::cout << "tellg returns " << in.tellg() << std::endl;
    std::cout << "after tell, good=" << in.good() << ", bad=" << in.bad()
        << ", fail=" << in.fail() << ", eof=" << in.eof() << std::endl;
}

尝试使用两个字节和十个字节的文件。

如果这些都没有给你带来任何快乐,那么应该让微软和/或GNU意识到这个问题。前者可以here,后者here

为了完整起见,我最初想到的唯一可能性是该文件虽然长度为三个字节,但在某种程度上是无效的。这取决于实际内容,因此,如果 只是abc,您可以放心地忽略它。

我在想的是具有两个字节BOM的Unicode文件和多字节Unicode代码点的第一个字节(例如,UTF-16),或者UTF-8的前三个字节。四字节代码点。

然而,如果您在二进制模式下打开它,那似乎难以置信,所以您可以放心地忽略它。

(a)对于它的价值而言, only 方式我可以在打开后设置failbit来删除文件。即使使用空文件也没有表现出您所描述的问题。