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

问题描述 投票:0回答:1

我碰到了一个奇怪的问题。假设我正在读这样一个文件:

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个字节的文件就是这种情况......

c++ c++11 fstream
1个回答
3
投票

在几条评论之后,显然ifstream构造函数本身在某种程度上失败了,因为failbit甚至在seekg调用之前就已经设置好了。

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

所以我有一些建议。

首先,使用文件的完整路径名,以确保您不可能在输入文件所在的目录中运行它。

其次,尝试以下完整的程序,该程序在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)对于它的价值,我唯一可以在开放后设置failbit的方法是删除文件。即使使用空文件也没有表现出您所描述的问题。

© www.soinside.com 2019 - 2024. All rights reserved.