当写入二进制文件时,`std::ofstream::write`有时会写入比应该写入的更多字节。

4
我将尝试将三维几何体写入二进制STL文件。以下是主程序的工作方式:
ParseSTL stl();
//generate the 3D model
std::string outfname = "test.stl";
std::ofstream outf(outfname, std::ios_base::out & std::ios_base::binary);
stl.writeBinarySTL(outf);

STL写入器是:

void writeBinarySTL(std::ofstream &outf)
{
    char attr[2] = { 0 };
    char header[80] = { 0 };
    int count = 0;
    outf.write(header, 80);
    //count += 80;
    //std::cout << "after header: file position: " << outf.tellp() << "  bytes written: " << count << "\n";
    //if ((int)outf.tellp() != count)
    //    std::cout << "something is wrong!\n";
    outf.write(reinterpret_cast<char *>(&facecount), sizeof(int));
    //count += sizeof(int);
    //std::cout << "after number of faces: file position: " << outf.tellp() << "  bytes written: " << count << "\n";
    //if ((int)outf.tellp() != count)
    //    std::cout << "something is wrong!\n";
    for (int i = 0; i < facecount; i++)
    {
        struct face{
            float n[3];
            float v[3][3];
        } f;
        for (int j = 0; j < 3; ++j)
            f.n[j] = (float) normals[i][j];
        for (int j = 0; j < 3; ++j)
            for (int k = 0; k < 3; ++k)
                f.v[j][k] = (float)vertices[faces[i][j]][k];
        outf.write(reinterpret_cast<char *>(&f), sizeof(f));
        //count += sizeof(f);
        //std::cout << "after struct: file position: " << outf.tellp() << "  bytes written: " << count << "\n";
        //if ((int)outf.tellp() != count)
        //{
        //    std::cout << "something is wrong!\n";
        //    break;
        //}
        outf.write(attr, 2);
        //count += 2;
        //std::cout << "after attributes: file position: " << outf.tellp() << "  bytes written: " << count << "\n";
        //if ((int)outf.tellp() != count)
        //{
        //    std::cout << "something is wrong!\n";
        //    break;
        //}
    }
    //std::cout << "Bytes written: " << count << "\n";
}

这些被注释掉的部分只是用于调试,facecount 是类 ParseSTL 的成员变量,用于存储三角形数量,normals 是一个 3D 向量的向量,存储所有面的法线,vertices 是一个 3D 向量的向量,存储所有顶点的坐标,faces 是一个由 3 个整数组成的向量,存储属于三角形的顶点的索引。现在,如果我运行程序,这是我得到的输出:

Vertex count = 4243
Face count = 3168
Edge count = 0
after header: file position: 80  bytes written: 80
after number of faces: file position: 84  bytes written: 84
after struct: file position: 132  bytes written: 132
after attributes: file position: 134  bytes written: 134
...
after struct: file position: 532  bytes written: 532
after attributes: file position: 534  bytes written: 534
after struct: file position: 583  bytes written: 582
something is wrong!

因此,看起来这行代码 outf.write(reinterpret_cast<char *>(&f), sizeof(f)); 写入了比它应该写入的多1个字节。偶尔会出现这种漂移,最终得到一个文件大小为 158,896 字节,而不是 158,484 字节。如果在写完结构体后添加 outf.seekp(count),则最终文件大小正确,但某些浮点数未被正确写入(因此漂移不总是在结构体末尾)。
我想知道我做错了什么,导致这些额外的字节被写入文件中。哦,我正在使用Microsoft Visual Stusio Express 2013。
1个回答

7

这行代码

std::ofstream outf(outfname, std::ios_base::out & std::ios_base::binary);

需要进行
std::ofstream outf(outfname, std::ios_base::out | std::ios_base::binary);
                                              ^^^^^ The difference

可以通过省略std::ios_base::out标志来简化。这也可以减少此类错误的出现机会(感谢@Blastfurnace的提示)。
std::ofstream outf(outfname, std::ios_base::binary);

啊,真倒霉。我本来在找“二进制”的,但看到它已经有了就跳过去了。 - Mooing Duck
糟糕,我怎么会错过那个。非常感谢 :-) 当计时器允许时,我会接受这个答案。 - triple_r
@triple_r,这种错误经常发生 :) - R Sahu
2
指定 std::ofstreamstd::ios_base::out 是冗余的。当使用文件名构造或打开 std::ofstream 时,该模式会自动包含在内。 - Blastfurnace

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接