2010-12-21 64 views
2

我有這兩個結構,我需要存儲在文件中。我找不到一個很好的方法來將它們解析成一個文件,而不用解析這個結構體,並將它寫成一個文本文件,這比我想要的效率低得多。將最基本的結構轉換爲文件的最簡單方法是什麼?結構是低於如何將結構存儲在文件中以輕鬆重新加載?

struct object 
{ 
    unsigned short id; 
    float x; 
    float y; 
    unsigned short type; 
    unsigned char flags; 
}; 

struct sector 
{ 
    unsigned long id; 
    unsigned long neighbors[4]; // North,East,South,West 
    std::vector<object> objects; 
}; 

我試過下面的代碼寫入到一個文件的結構,但它不工作得很好。執行後文件的大小隻有4.7kb,但它應該大得多。

sector s; 
object o; 
s.id = 1; 
s.neighbors = {2, 3, 4, 5}; 
o.id = 1; o.x = 2.0f; o.y = 3.0f; o.type = 4; o.flags = 6; 
for(int i = 0; i < 65536; i++) 
{ 
    s.objects.push_back(o); 
    o.id += 1; o.x += 1.0f; o.y += 1.0f; o.type += 1; o.flags += 1; 
} 

ofstream os("world.dat", ios::binary|ios::out); 
s.objects.resize(s.objects.size()); 
int size = s.objects.size() * sizeof(object); 
os.write((char*)&size, sizeof(int)); 
os.write((char*)&s, size); 
os.close(); 

有什麼建議?

+0

您是否嘗試輸出將內存直接保存到磁盤?例如,從`&o`到`byte`數組的`memcpy`,並將其保存爲二進制數據到磁盤 – Itsik 2010-12-21 20:38:04

+0

那麼如果它只有4.7kb?你有沒有試過從磁盤讀回它,看它是否有效?如果是,你就設置好了。 – 2010-12-21 20:41:21

+0

@Itsik基本上就是他沒有將數據複製到內存中的差異位置。 – 2010-12-21 20:41:54

回答

3

您不能使用原始字節I/O編寫包含向量的結構。 vector類是一個小數據結構,它將數據存儲在堆的某個地方,而不是存儲在結構中。這是因爲結構不可能提前「知道」它將容納多少個對象。

你可以這樣寫向量的內容:

os.write((const char*)&s.id, sizeof(s.id)); 
os.write((const char*)&s.neighbors, sizeof(s.neighbors)); 
os.write((const char*)&s.objects[0], size); 

至於爲何文件,其中僅有4.7 kb的它結束了,我不知道。打印出size以查看正在寫入多少數據。我在上述更改後檢查了代碼,並且它工作正常。另外,你不需要s.objects.resize(s.objects.size());。將矢量調整到其自己的大小是多餘的。

另外請注意一個小怪癖。 sizeof(object)== 16在我的體系結構中,這比以上結構(2 + 4 + 4 + 2 + 1 == 13)所需要的要多。編譯器通常添加填充,以確保尺寸2 Ñ的原語被對準到2 Ñ字節邊界,這導致每個結構體內部的空穴和在該載體結構之間。

這樣做的結果是您正在向文件寫入額外的字節,其中一些是隨機噪聲。在非調試版本中,這些漏洞永遠不會被填充任何東西,所以它們只包含在爲了您的目的而分配之前在該內存位置處的任何垃圾。因此,如果您運行該程序兩次,這兩個文件可能不會完全相同。

0

我想我只是想出了一個解決方案。對象的數量是一個常數,所以使用矢量是不必要的。我用object objects[256][256]替換了vector<object> objects,它用我當前的代碼正確寫入文件。我也放棄了跟蹤一個部門相對於另一個部門的位置,由id和鄰居id支持x,y座標系統。應該更容易跟蹤。我希望我知道爲什麼我總是過於複雜的東西然後簡化他們..

struct object 
{ 
    unsigned short id; 
    float x; 
    float y; 
    unsigned short type; 
    unsigned char flags; 
}; 
struct sector 
{ 
    unsigned long x; 
    unsigned long y; 
    object objects[256][256]; 
}; 
sector s; 
object o; 

s.x = 1; s.y = 1; 
o.id = 1; o.x = 2.0f; o.y = 3.0f; o.type = 4; o.flags = 6; 
for(int x = 0; x < 256; x++) 
{ 
    for(int y = 0; y < 256; y++) 
    { 
     s.objects[x][y] = o; 
     o.id += 1; o.x += 1.0f; o.y += 1.0f; o.type += 1; o.flags += 1; 
    } 
} 

ofstream os("world.dat", ios::binary|ios::out); 
int size = sizeof(sector); 
os.write((char*)&s, size); 
os.close(); 

這是正常工作。我想我正在做的是建立一個2D地圖,每個節點都包含它自己的2D地圖。也許有更好的辦法。

4

聽起來像你可以使用序列化庫,如boost::serialization。這支持STL容器,因此在示例中支持結構應該非常簡單。

0

你看過fread()fwrite()?如果你並不需要人爲的可讀性 - 該文件,對象和部門都莢,那麼這樣的事情應該爲你工作:

object o; 
FILE * fh = ...; 
... 
fwrite(&o, sizeof(o), 1, fh); 

fread(&o, sizeof(o), 1, fh); 

通常我不會建議這種面向C編碼,但有時舊的方式仍然是最簡單的。

注意,該代碼需要扇區的陣列中的對象爲恆定的大小。

0

如果你想知道爲什麼只有4.7K被存儲在文件中,你需要說你正在使用和C++編譯器,OS。由於'''在堆棧中,所以當你選擇寫'&'到文件時,只有4.7K的堆棧被使用是合理的假設。在Windows上,環境塊佔用堆棧空間3.8K。因此,在Windows上,您的應用程序在您選擇調用'& s'上的write()時使用了額外的0.9K堆棧空間(在環境塊之後),並且由於堆棧向下增長,C++實現(默默地)寫入(),直到堆棧開始的位置,即比'& s'高4.7K。

0

如果你想避免使用庫,那麼你的結構應該是POD。然後,您可以將整個結構存儲在二進制文件中。否則,您可能會在堆上分配數據。

相關問題