2013-04-20 112 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; 
}