fstream 产生非常奇怪的行为

fstream produces REALLY weird behavior

当我将双精度写入文件流,然后写入一个整数时,整数作为额外数字附加到双精度,我不知道为什么会这样。有人可以为我解释一下吗?最小示例:

#include <iostream>
#include <fstream>

int main()
{
    std::fstream s("test.bin", std::fstream::binary | std::fstream::trunc | std::fstream::in | std::fstream::out);
    s << 3.14;
    int n = 36;
    s << n;
    s.seekp(0);
    double d;
    s >> d;
    printf("%f\n", d);
}

我期望发生的事情:

实际情况: 程序输出 3.143600 - 我完全不知道为什么会这样。这是零意义。如果我改变初始值,比如从 3.1418.3204,那么它会输出 18.320436。发生什么事了?

对流进行操作时,<<>> 执行格式化访问。忽略幕后巫术,<< 写入字符串而 >> 读取字符串。所以

s << 3.14;` 

将 3.14 转换为字符串并将该字符串写入文件。与 s << n; 相同。

您现在有一个包含字符“3.1436”的文件。

s >> d;

将文件作为字符串读取,寻找分隔空格或任何其他不能转换为双精度值的字符。由于文件中没有分隔 3.14 和 36 的内容,因此将 3.1436 作为单个数字读回。

您需要做的是使用原始的、未格式化的读写:

#include <iostream>
#include <fstream>

int main()
{
    std::fstream s("test.bin",
                   std::fstream::binary | std::fstream::trunc |
                       std::fstream::in | std::fstream::out);
    double d = 3.14;
    int n = 36;
    if (s.write((char*) &d, sizeof(d)) &&
        s.write((char*) &n, sizeof(n)))
    { 
        s.seekp(0);
        if (s.read((char*) &d, sizeof(d)))
        { 
            std::cout << d;
        }
        else 
        { 
             std::cerr << "failed to read\n";
        }
    }
    else
    {
         std::cerr << "failed to write\n";
    }
}

始终测试 IO 以确保它成功。

另请注意,这并不是那么便携。如果不加小心,不能保证在一台机器上写入的文件在另一台机器上可读。 int 尺码可能不同,当心 the endian 我的儿子!字节的顺序...

Documentation on write

Documentation on read

It writes the value 3.14 to the file (8 bytes)
It writes the value 36 to the file (4 bytes)

这不是发生的事情。 >><< 以及朋友以人类可读的形式读写值。

s << 3.14; 将数字 3、句号、数字 1 和数字 4 写入文件(4 个 ASCII 字符)。 s << 36; 将数字 3 和数字 6 写入文件(2 个 ASCII 字符)。

文件然后包含 6 个 ASCII 字符:一个 3、一个句点、一个 1、一个 4、一个 3 和一个 6。或者像任何正常人会​​写的那样:它包含 3.1436

s >> d; 从文件中按字符读取数字,直到找到一个看起来不像数字的字符,然后将读取的字符转换为数字(与他们如果您将它们键入 cin),则会被转换。它读取 3,句点,1、4、3、6,然后生成数字 3.1436。