2013-04-20 128 views
1

我有一个读取.ASE文件的类,需要将变量存储在二进制文件中,以便下次运行应用程序时能更快地访问。我将我的信息存储在结构中以使写入过程更加简单。这是结构我使用,在标头中定义:定义变量讨厌的错误阅读结构从二进制文件(C++)

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

我已经创建了这样的一个实例也STRUCT在报头中:

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); 

现在它不起作用。结构的int变量是正确获取的,但矢量变量以下面的形式出现???有内存错误。我对C++很陌生,这可能是一个愚蠢的问题,但我不明白。我也尝试过ofstream和ifstream的C++函数,并且遇到同样的问题。

在此先感谢。

回答

1

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

这件事情,就像你说:

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

如果打印矢量文件,你实际上是打印的地址。这就是为什么它没有失败,如果你在同一次运行中执行保存和加载 - 地址没有改变,所以它只是拿起你离开的地方。但是,如果您不填充矢量并将其保存在前面,则您已保存的地址将指向无效,导致非法内存访问。

要合理保存矢量,首先保存矢量的大小,然后迭代并保存每个元素,或使用Boost Serialization

+0

解决!我一个接一个地存储矢量内容和矢量的大小,而不是矢量本身。现在我可以在不写文件的情况下访问它。 – davidkyoku 2013-04-20 14:00:26

1

问题是,这不会使写入过程更容易,它只是使它错了。

对于fwrite(或通过使用C++等价物),您不能输出像向量这样的复杂对象。你必须努力做到这一点。

我不能给出任何具体的建议,因为我不知道Vector2Vector3的定义。但基本上你必须输出矢量的大小,然后输出每个元素的大小。如果这些元素本身就是复杂的对象,那么你必须特别处理这些元素。你对输入做相反的处理。

0

向量不保存向量对象本身的数据 - 它们包含指向不同堆分配内存的指针。您正在保存和恢复指针,但对向量中指向的数据无所作为。我建议你阅读boost序列化库教程...它应该让你开始一个高效的方向。

+0

点上。在我看来,使用C++序列化本身会使代码更具可读性。 – Ram 2013-04-20 13:43:44

1

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

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

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

希望这有助于。

0

下面是一些示例代码来引用,如果你有麻烦(注:顶点是交错的,不分开,你是):

的Vector2D:

#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 

的Vector3D:

#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; 
}