Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
无结构元数据本身的C#序列化_C#_File_Object_Serialization_Struct - Fatal编程技术网

无结构元数据本身的C#序列化

无结构元数据本身的C#序列化,c#,file,object,serialization,struct,C#,File,Object,Serialization,Struct,现在我正在开发一个游戏引擎。为了更高效地保存来自最终用户的数据,我尝试在修改后的Wavefront*.OBJ格式上使用序列化。我设置了多个结构来表示数据,对象的序列化工作得很好,只是它占用了大量的文件空间(至少是原始OBJ文件的5倍) 具体来说,这里有一个关于最终对象的快速示例(JSON格式): 基本上,我对序列化数据(二进制格式)方法的主要问题是它保存结构的名称,而不是值。我希望将数据保持在我已有的格式,而不必将结构本身保存在数据中。我想保存与上面类似的内容,但它仍然允许我稍后使用不同的结构名

现在我正在开发一个游戏引擎。为了更高效地保存来自最终用户的数据,我尝试在修改后的Wavefront*.OBJ格式上使用序列化。我设置了多个结构来表示数据,对象的序列化工作得很好,只是它占用了大量的文件空间(至少是原始OBJ文件的5倍)

具体来说,这里有一个关于最终对象的快速示例(JSON格式):

基本上,我对序列化数据(二进制格式)方法的主要问题是它保存结构的名称,而不是值。我希望将数据保持在我已有的格式,而不必将结构本身保存在数据中。我想保存与上面类似的内容,但它仍然允许我稍后使用不同的结构名重新编译

以下是我正在序列化并保存到文件中的主要对象:

[Serializable()] //the included structs have this applied
public struct InstantGameworksObjectData
{
    public Position[] Positions;
    public TextureCoordinates[] TextureCoordinates;
    public Position[] Normals;

    public Face[] Faces;
}
以下是我序列化和保存数据的方法:

IFormatter formatter = new BinaryFormatter();

long Beginning = DateTime.Now.Ticks / 10000000;
foreach (string file in fileNames)
{
    Console.WriteLine("Begin " + Path.GetFileName(file));

    var output = InstantGameworksObject.ConvertOBJToIGWO(File.ReadAllLines(file));

    Console.WriteLine("Writing file");

    Stream fileOutputStream = new FileStream(outputPath + @"\" + Path.GetFileNameWithoutExtension(file) + ".igwo", FileMode.Create, FileAccess.Write, FileShare.None);
    formatter.Serialize(fileOutputStream, output);


    Console.WriteLine(outputPath + @"\" + Path.GetFileNameWithoutExtension(file) + ".igwo");
}
当然,输出是二进制/十六进制的(取决于您用来查看文件的程序),这很好:

但将其在线放入十六进制到文本转换器会产生特定的名称数据:


从长远来看,这可能意味着千兆字节的无用数据。如何以正确的格式保存包含数据的C#对象,而不产生额外的元数据混乱?

正如您正确指出的,标准框架二进制格式化程序包含大量关于数据结构的元数据。这是为了使序列化的数据保持自我描述。如果他们将数据与所有元数据分离,那么对类结构的最小更改将使以前序列化的数据变得无用。出于这个原因,我怀疑您是否会找到任何标准的框架方法来序列化二进制数据,而这些方法没有包含所有元数据

即使ProtoBuf也包含文件数据中数据的语义,尽管开销较小

假设数据的结构遵循合理常见且成熟的3D对象数据形式,那么您可以为资产使用自己的格式,该格式将语义剥离,只存储原始数据。您可以使用BinaryReader/BinaryWriter类轻松实现读写方法(这是我的首选)。如果您希望混淆来自最终用户的数据,有多种不同的方法可以通过这种方法实现

例如:

public static InstantGameworksObjectData ReadIgoObjct(BinaryReader pReader)
{
    var lOutput = new InstantGameworksObjectData();

    int lVersion = pReader.ReadInt32();     // Useful in case you ever want to change the format

    int lPositionCount = pReader.ReadInt32();   // Store the length of the Position array before the data so you can pre-allocate the array.
    lOutput.Positions = new Position[lPositionCount];
    for ( int lPositionIndex = 0 ; lPositionIndex < lPositionCount ; ++ lPositionIndex )
    {
        lOutput.Positions[lPositionIndex] = new Position();
        lOutput.Positions[lPositionIndex].X = pReader.ReadSingle();
        lOutput.Positions[lPositionIndex].Y = pReader.ReadSingle();
        lOutput.Positions[lPositionIndex].Z = pReader.ReadSingle();
        // or if you prefer...  lOutput.Positions[lPositionIndex] = Position.ReadPosition(pReader);
    }

    int lTextureCoordinateCount = pReader.ReadInt32();
    lOutput.TextureCoordinates = new TextureCoordinate[lPositionCount];
    for ( int lTextureCoordinateIndex = 0 ; lTextureCoordinateIndex < lTextureCoordinateCount ; ++ lTextureCoordinateIndex )
    {
        lOutput.TextureCoordinates[lTextureCoordinateIndex] = new TextureCoordinate();
        lOutput.TextureCoordinates[lTextureCoordinateIndex].X = pReader.ReadSingle();
        lOutput.TextureCoordinates[lTextureCoordinateIndex].Y = pReader.ReadSingle();
        lOutput.TextureCoordinates[lTextureCoordinateIndex].Z = pReader.ReadSingle();
        // or if you prefer...  lOutput.TextureCoordinates[lTextureCoordinateIndex] = TextureCoordinate.ReadTextureCoordinate(pReader);
    }

    // ...
}
publicstaticinstantgameworksobjectdata ReadIgoObjct(二进制读取器前置器)
{
var lOutput=new InstantGameworksObjectData();
int lVersion=pReader.ReadInt32();//在需要更改格式时非常有用
int lPositionCount=pReader.ReadInt32();//在数据之前存储位置数组的长度,以便可以预先分配数组。
lOutput.Positions=新位置[lPositionCount];
对于(int-lPositionIndex=0;lPositionIndex
就空间效率和速度而言,这种方法很难被击败。但是,这对于三维对象很有效,因为它们定义得相当清楚,并且格式不太可能更改,但是这种方法可能无法很好地扩展到要存储的其他资源

如果您发现需要经常更改类结构,那么您可能会发现必须根据版本编写大量的If块才能正确读取文件,并且必须定期调试文件中数据格式与您期望的格式不符的问题。在对数据对象类的结构感到满意之前,最好在大部分开发中使用ProtoBuf之类的工具,然后在发布之前为每个数据对象类编写原始二进制读/写方法

我还建议进行一些单元测试,以确保您的读写方法正确地持久化了对象,从而避免了以后的麻烦


希望这有帮助

它不是无用的-二进制格式化程序需要它来反序列化。查看ProtoBuf网络您想要ProtoBuf.NET或Json这正是我想要的,谢谢。令人失望的是,这不是一个已经内置到.NET中的东西。我最初问题中的措辞有点混乱,但我认为现在最能描述它的术语是“未标记数据”
public static InstantGameworksObjectData ReadIgoObjct(BinaryReader pReader)
{
    var lOutput = new InstantGameworksObjectData();

    int lVersion = pReader.ReadInt32();     // Useful in case you ever want to change the format

    int lPositionCount = pReader.ReadInt32();   // Store the length of the Position array before the data so you can pre-allocate the array.
    lOutput.Positions = new Position[lPositionCount];
    for ( int lPositionIndex = 0 ; lPositionIndex < lPositionCount ; ++ lPositionIndex )
    {
        lOutput.Positions[lPositionIndex] = new Position();
        lOutput.Positions[lPositionIndex].X = pReader.ReadSingle();
        lOutput.Positions[lPositionIndex].Y = pReader.ReadSingle();
        lOutput.Positions[lPositionIndex].Z = pReader.ReadSingle();
        // or if you prefer...  lOutput.Positions[lPositionIndex] = Position.ReadPosition(pReader);
    }

    int lTextureCoordinateCount = pReader.ReadInt32();
    lOutput.TextureCoordinates = new TextureCoordinate[lPositionCount];
    for ( int lTextureCoordinateIndex = 0 ; lTextureCoordinateIndex < lTextureCoordinateCount ; ++ lTextureCoordinateIndex )
    {
        lOutput.TextureCoordinates[lTextureCoordinateIndex] = new TextureCoordinate();
        lOutput.TextureCoordinates[lTextureCoordinateIndex].X = pReader.ReadSingle();
        lOutput.TextureCoordinates[lTextureCoordinateIndex].Y = pReader.ReadSingle();
        lOutput.TextureCoordinates[lTextureCoordinateIndex].Z = pReader.ReadSingle();
        // or if you prefer...  lOutput.TextureCoordinates[lTextureCoordinateIndex] = TextureCoordinate.ReadTextureCoordinate(pReader);
    }

    // ...
}