1

我有一个用于读取 .ASE 文件的类,并且需要将变量存储在二进制文件中,以便在下次应用程序运行时更快地访问。我将我的信息存储在一个结构中,以使编写过程更容易。这是我使用的结构,在标题中定义:

struct myMesh{
    std::vector<Vector3> vertices;
    std::vector<Vector2> uvs;
    std::vector<Vector3> normals;
    int verticesSize;
    int uvsSize;
    int normalsSize;
};

我还在标题中创建了这个结构的一个实例来定义变量:

myMesh myInfo;

将数据存储在结构变量中后,我使用 C 函数编写了一个二进制文件:

std::string path = filename + ".bin";
const char * c = path.c_str();

FILE *pBinaryFile;
pBinaryFile = fopen(c, "wb");
if (pBinaryFile==NULL){
    std::cout << "error";
}
fwrite(&myInfo.vertices, sizeof(myInfo), 1, pBinaryFile);
fclose(pBinaryFile);

为了测试二进制文件是否正确创建,我读取了文件并创建了另一个结构实例来可视化数据:

myMesh _myInfo;
FILE *theFile;
theFile = fopen(c, "rb");
if (theFile==NULL){
    std::cout << "error";
}
fread(&_myInfo, sizeof(_myInfo), 1, theFile);
fclose(theFile);

这很好用。当我只尝试读取文件时出现问题,而不是使用写入过程:

/*FILE *pBinaryFile;
pBinaryFile = fopen(c, "wb");

if (pBinaryFile==NULL){
    std::cout << "error";
}

fwrite(&myInfo.vertices, sizeof(myInfo), 1, pBinaryFile);
fclose(pBinaryFile);*/


myMesh _myInfo;
FILE *theFile;
theFile = fopen(c, "rb");
if (theFile==NULL){
    std::cout << "error";
}
fread(&_myInfo, sizeof(_myInfo), 1, theFile);
fclose(theFile);

现在它不起作用。正确获取了struct的int变量,但是vector变量出现的形式是???内存错误。我对 C++ 很陌生,这可能是一个愚蠢的问题,但我不明白这一点。我还尝试了 ofstream 和 ifstream 的 C++ 函数,我也遇到了同样的问题。

提前致谢。

4

5 回答 5

1

问题是这并没有让写作过程变得更容易,它只会让它出错。

您不能使用对 fwrite 的单个调用(或使用 C++ 等效项)输出复杂的对象,例如向量。你必须以艰难的方式去做。

我无法给出任何具体建议,因为我不知道 和 的Vector2定义Vector3。但基本上你必须输出向量的大小,然后是它的每个元素。如果这些元素本身就是复杂的对象,那么您还必须特别处理这些对象。你在输入上做相反的事情。

于 2013-04-20T13:36:52.497 回答
1

您无法通过询问其大小来保存结构,因为您保存的数据不是基本的本机类型。您必须编写一个自定义序列化函数来写入/读取结构的每个元素。

通过获取向量的长度和单位元素(例如 Vector3/Vector2)的大小来保存 std::vector,然后保存它。

另外,我注意到您正在使用 C 函数来创建和读取文件。这太不酷了。使用 C++ 见http://www.cplusplus.com/doc/tutorial/files/

希望这可以帮助。

于 2013-04-20T13:39:35.307 回答
1

std::vector 将在堆上分配空间,并且只保留向量对象本身的指针。

就像你说的那样:

Type* array = new Type[10];  // array's value is a memory address, NOT the array itself

如果将矢量打印到文件中,实际上是在打印地址。这就是为什么在同一次运行中执行保存和加载不会失败的原因——地址没有改变,所以它只是从你离开的地方开始。但是如果你不填充向量并将其保存在前面,那么你已经保存的地址将指向任何内容,从而导致非法内存访问。

要合法地保存向量,请先保存向量的大小,然后对其进行迭代并保存每个元素,或者使用Boost Serialization

于 2013-04-20T13:46:44.210 回答
0

向量不会在向量对象本身中保存它们的数据——它们持有指向不同堆分配内存的指针。您正在保存和恢复指针,但对向量内的指向数据不做任何事情。我建议您阅读 boost 序列化库教程……它应该让您开始朝着富有成效的方向发展。

于 2013-04-20T13:39:16.850 回答
0

如果您遇到问题,请参考以下示例代码(注意:顶点是交错的,而不是像您的那样分开):

矢量二维:

#ifndef VECTOR2D_H_
#define VECTOR2D_H_

struct Vector2D
{
    union
    {
        struct { float x,y; };
        struct { float s,t; };
        struct { float u,v; };
        float e[2];
    };
    Vector2D(): x(0.0f),y(0.0f) {}
    Vector2D(const float _x,const float _y): x(_x),y(_y) {}
};

#endif 

矢量3D:

#ifndef VECTOR3D_H_
#define VECTOR3D_H_

struct Vector3D
{
    union
    {
        struct { float x,y,z; };
        struct { float s,t,r; };
        float e[3];
    };

    Vector3D() :x(0.0f),y(0.0f),z(0.0f) {}
    Vector3D(const float _x,const float _y,const float _z): x(_x),y(_y),z(_z) {}
};

#endif

顶点:

#ifndef VERTEX_H_
#define VERTEX_H_
#include "Vector2D.h"
#include "Vector3D.h"

struct Vertex
{
    Vector3D    pos;
    Vector3D    nrm;
    Vector2D    tex;

    Vertex() {}
    Vertex(const Vector3D& _pos,const Vector3D& _nrm,const Vector2D& _tex)
        :pos(_pos),nrm(_nrm),tex(_tex) {}
};

#endif

网:

#ifndef MESH_H_
#define MESH_H_
#include <vector>
#include "Vertex.h"
#include <sstream>

struct MyMesh
{
    std::vector<Vertex> verts;
    unsigned numVerts;

    void    WriteOut(std::ostringstream& oss)
    {
        numVerts = verts.size();
        oss.write((const char*)&numVerts,sizeof(numVerts));
        unsigned totalSize = numVerts * sizeof(Vertex);
        oss.write((const char*)verts.data(),totalSize);
    }
    void    ReadIn(std::istringstream& iss)
    {
        iss.read((char*)&numVerts,sizeof(numVerts));
        verts.resize(numVerts);
        iss.read((char*)verts.data(),numVerts*sizeof(Vertex));
    }
};

#endif

和一个测试 main.cpp:

#include "Mesh.h"
#include <sstream>
#include <fstream>
#include <iostream>

void PopulateMesh(MyMesh& mesh)
{
    // Fill the mesh with some vertices
    for(int i=0; i<3; ++i)
    {
        Vector3D tempVec(0.0f,i,0.0f);
        Vector2D tempTex(0.0f,i);
        Vertex temp(tempVec,tempVec,tempTex);
        mesh.verts.push_back(temp);
    }
}
void PrintMesh(const MyMesh& mesh)
{
    for(auto i=0u; i<mesh.verts.size(); ++i)
    {
        std::cout << "Position: " << mesh.verts[i].pos.x << ' ' << mesh.verts[i].pos.y << ' ' << mesh.verts[i].pos.z << '\n';
        std::cout << "Normal: " << mesh.verts[i].nrm.x << ' ' << mesh.verts[i].nrm.y << ' ' << mesh.verts[i].nrm.z << '\n';
        std::cout << "Tex Coords: " << mesh.verts[i].tex.u << ' ' << mesh.verts[i].tex.v << "\n\n";
    }
}
void WriteStreamToFile(std::ostringstream& oss)
{
    std::ofstream fout;
    fout.open("test.bin",std::ios_base::binary | std::ios_base::out);
    if(fout.is_open())
    {
        fout.write(oss.str().c_str(),oss.str().size());
        fout.close();
    }
}
void ReadStreamFromFile(std::istringstream& iss)
{
    std::string file;
    std::ifstream fin;
    fin.open("test.bin",std::ios_base::binary | std::ios_base::in | std::ios_base::_Nocreate);
    if(fin.is_open())
    {
        std::getline(fin,file,'\x1A');

        fin.close();
    }
    iss.str(file);
}

int main()
{
    MyMesh outMesh;
    unsigned numMeshes = 1;

    PopulateMesh(outMesh);
    PrintMesh(outMesh);

    // Write to the stream
    std::ostringstream oss(std::ios_base::binary | std::ios_base::out);
    oss.write((const char*)&numMeshes,sizeof(numMeshes));
    outMesh.WriteOut(oss);

    WriteStreamToFile(oss);

    std::istringstream iss(std::ios_base::binary | std::ios_base::in);
    ReadStreamFromFile(iss);

    // Read from the stream
    iss.read((char*)&numMeshes,sizeof(numMeshes));

    MyMesh inMesh;
    inMesh.ReadIn(iss);
    PrintMesh(inMesh);

    return 0;
}
于 2013-04-20T14:54:57.530 回答