2010-12-21 78 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。然后,您可以将整个结构存储在二进制文件中。否则,您可能会在堆上分配数据。

相关问题