std::ifstream::read() 读取少于请求并无明显原因设置故障位

std::ifstream::read() reading less than requested and setting failbit for no obvious reason

我试图使用 std::ifstream 将整个文件读入缓冲区,但没有明显的原因失败,所以我构建了一个演示问题的最小代码示例:

std::vector<char> vec;
vec.resize(1000);
std::ifstream file("G:/Pictures/Webcam/Snapshot_20110209.jpg");
file.exceptions(std::ifstream::badbit | std::ifstream::failbit | std::ifstream::eofbit);
std::cout << file.good() << std::endl;
try {
    file.read(vec.data(), 100);
} catch (std::ios_base::failure f) {
    std::cout << f.what() << " Characters extracted: " << file.gcount() << std::endl;
} catch (...) {
    std::cout << "Some other error" << std::endl;
}
std::cout << "Done" << std::endl;
file.close();

我要读取的文件大小为 48kb,因此读取 100 字节应该不是问题。 1000 字节大的缓冲区,这样应该也可以。现在,发生的情况是流仅读取 61 个字节,然后设置 failbit。生成的输出如下:

1
ios_base::failbit set: iostream stream error Characters extracted: 61
Done

所以出于某种原因,故障位设置在 61 字节之后。如果我读取少于 61 个字节,它就可以工作。如果我尝试阅读更多内容,它也会在 61 处失败。我还尝试了其他类似大小的文件,同样的问题。一些完全不同的不同大小的文件表现出相同的行为,但在 166 字节之后。

现在,如果我使用 Qt 的 QFile class 读取数据,一切正常,我可以读取完整的文件。代码看起来像这样:

QFile file(path);
std::vector<char> buffer;
buffer.resize(file.size());
if (!file.open(QIODevice::ReadOnly)) return;
file.read(buffer.data(), file.size());
file.close();

我知道,现在你会说我只读了文件的大小,但实际上超过了 61 个字节。同样读一个固定的100也没问题。

std::ifstream file("G:/Pictures/Webcam/Snapshot_20110209.jpg");

糟糕!您正在以 文本模式.

打开文件

根据您的平台,任何数量的讨厌的二进制字符都可能使流认为数据流已经结束,因为不同的平台使用不同的 "sentinel characters" 来表示这一点(例如 Ctrl+Z 或 0x1A on Windows — 字节 62 处是否有 0x1A1).

这里:

std::ifstream file("G:/Pictures/Webcam/Snapshot_20110209.jpg", std::ios::binary);

1 我在该位置有一个带有 0x05 的 JPEG 文件;快速浏览 an EXIF format description 让我觉得我们都在查看描述水平分辨率编码的 TIFF 数据字段,因为 0x1A010x0500 是常见选项。