我遇到了一个特殊的问题。假设我正在读这样一个文件:
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字节的文件就是这种情况......
答案 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
来删除文件。即使使用空文件也没有表现出您所描述的问题。