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
在打开是删除文件。即使使用空文件也没有出现您描述的问题。
我运行遇到了一个奇怪的问题。假设我正在读取这样的文件:
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
在打开是删除文件。即使使用空文件也没有出现您描述的问题。