tellg() returns -1 仅适用于小文件

tellg() returns -1 only for small files

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

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 个字节的文件会出现这种情况...

经过一些评论,很明显 ifstream 构造函数本身在某种程度上失败了,因为 failbit 甚至 之前设置了 seekg打电话。

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

所以我有一些建议。

首先,使用文件的 完整 路径名只是为了确保您 运行 它不可能在目录 other 比输入文件所在的位置。

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

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

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

如果 none 这让您感到高兴,Microsoft and/or GNU 应该意识到这个问题。前者可以做到here, the latter here.


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

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

但是,如果您以二进制模式打开它,这似乎难以置信不太可能,因此您可以安全地忽略它。


(a) 对于它的价值,只有 方法我可以得到这个 failbit 在打开是删除文件。即使使用空文件也没有出现您描述的问题。