【问题标题】:List Serialization and Deserialization by binary formatter二进制格式化程序的列表序列化和反序列化
【发布时间】:2012-08-28 22:08:55
【问题描述】:

我有课。我想序列化并序列化一个包含该类对象的列表。我想使用二进制格式化程序。 这是我的课:

[Serializable]
public class Section :ISerializable
{
    private double ClearCover;
    private string SectionName;

    private double Diameter;

    public double Height;
    private double Width;

    private double InternalDiameter;
    private double ExternalDiameter;

    private double InternalHeight;
    private double ExternalHeight;
    private double InternalWidth;
    private double ExternalWidth;

    private double WebWidth;
    private double FlangeWidth;
    private double FlangeThickness;



    public double clearCover
    {
        get { return ClearCover; } 
        set { ClearCover = value; }
    }
    public string sectionName
    {
        get{return SectionName;} 
        set{SectionName=value;} 
    }

    public double diameter
    {
        get { return Diameter; } 
        set { Diameter = value; }
    }

    public double height
    {
        set { Height = value; }
        get { return Height; }
    }
    public double width
    {
        set { Width = value; }
        get { return Width; }
    }

    public double internalDiameter
    {
        set { InternalDiameter = value; } 
        get { return InternalDiameter; }
    }
    public double externalDiameter
    {
        set { ExternalDiameter = value; } 
        get { return ExternalDiameter; }
    }

    public double internalHeight
    {
        set { InternalHeight = value; }
        get { return InternalHeight; }
    }
    public double externalHeight
    {
        set { ExternalHeight = value; } 
        get { return ExternalHeight; }
    }
    public double internalWidth
    {
        set { InternalWidth = value; } 
        get { return InternalWidth; }
    }
    public double externalWidth
    {
        set { ExternalWidth = value; } 
        get { return ExternalWidth; }
    }

    public double flangeWidth
    {
        set { FlangeWidth = value; }
        get { return FlangeWidth; }
    }
    public double flangeThickness
    {
        set { FlangeThickness = value; }
        get { return FlangeThickness; }
    }
    public double webWidth
    {
        set { WebWidth = value; }
        get { return WebWidth; }
    }




    public Section() { }

    protected Section(SerializationInfo info, StreamingContext context)
    {
        sectionName = info.GetString("Section Name");
        clearCover = info.GetDouble("Clear Cover");

        diameter = info.GetDouble("Diameter");

        //internalDiameter = info.GetDouble("Internal Diameter");
        //externalDiameter = info.GetDouble("External Diameter");


        height = info.GetDouble("Height");
        width = info.GetDouble("Width");



        internalHeight = info.GetDouble("Internal Height");
        externalHeight = info.GetDouble("External Height");
        internalWidth = info.GetDouble("Internal Width");
        externalWidth = info.GetDouble("External Width");

        flangeWidth = info.GetDouble("Flange Width");
        flangeThickness = info.GetDouble("Flange Thickness");
        webWidth = info.GetDouble("Web Width");



    }

    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Section Name", sectionName);
        info.AddValue("Clear Cover", clearCover);

        info.AddValue("Diameter",diameter);

        //info.AddValue("Internal Diameter", internalDiameter);
        //info.AddValue("External Diameter", externalDiameter);

        info.AddValue("Height",height);
        info.AddValue("Width",width);

        info.AddValue("Internal Height",internalHeight);
        info.AddValue("External Height",externalHeight);
        info.AddValue("Internal Width",internalWidth);
        info.AddValue("External Width",externalWidth);

        info.AddValue("Flange Width",flangeWidth);
        info.AddValue("Flange Thickness", flangeThickness);
        info.AddValue("Web Width", webWidth);


    }


}

我在序列化方面没有任何问题。但是对于反序列化,它可以只反序列化第一个对象而不是所有对象。我该怎么办,请帮帮我!

【问题讨论】:

    标签: list serialization binary deserialization


    【解决方案1】:

    从OP的另一封邮件中,获得了以下方法(我整理了一点,不多):

    static void Serialize(object obj, string filename)
    {
        using (FileStream streamOut = new FileStream(filename, FileMode.Append))
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(streamOut, obj);
        }
    }
    
    
    public static List<Section> DeserializeList(string filename)
    {
        using (FileStream streamIn = File.OpenRead(filename))
        {
            BinaryFormatter formatter = new BinaryFormatter();
            return (List<Section>) formatter.Deserialize(streamIn);
        }
    }
    

    这里的关键观察是假设BinaryFormatter是一种可附加格式,并且顺序序列化两个对象与同时序列化两个项目(一个列表)相同,例如:

    if(File.Exists("foo.bin")) File.Delete("foo.bin"); // start afresh
    Serialize(new Section { Diameter = 1.2, ClearCover = 3.4 }, "foo.bin");
    Serialize(new Section { Diameter = 5.6, ClearCover = 7.8 }, "foo.bin");
    
    var clone = DeserializeList("foo.bin");
    

    然而,并非如此。要以这种方式反序列化项目,我们必须执行以下操作:

    public static List<Section> DeserializeList(string filename)
    {
        using (FileStream streamIn = File.OpenRead(filename))
        {
            List<Section> list = new List<Section>();
            BinaryFormatter formatter = new BinaryFormatter();
            while(streamIn.Position != streamIn.Length)
            {
                list.Add((Section) formatter.Deserialize(streamIn));
            }
            return list;
        }
    }
    

    这有点令人烦恼 - 尤其是因为它不能应用于所有流(.Length 甚至 .Position 都不是普遍可用的)。

    上述应该可以工作,但我强烈建议使用可附加的格式,例如 protobuf。事实上,就模型而言,protobuf-net 让这个场景变得毫不费力:

    [ProtoContract]
    public class Section
    {
        [ProtoMember(1)] public double ClearCover { get; set; }
        [ProtoMember(2)] public string SectionName { get; set; }
        [ProtoMember(3)] public double Diameter { get; set; }
        [ProtoMember(4)] public double Height { get; set; }
        [ProtoMember(5)] public double Width { get; set; }
        [ProtoMember(6)] public double InternalDiameter { get; set; }
        [ProtoMember(7)] public double ExternalDiameter { get; set; }
        [ProtoMember(8)] public double InternalHeight { get; set; }
        [ProtoMember(9)] public double ExternalHeight { get; set; }
        [ProtoMember(10)] public double InternalWidth { get; set; }
        [ProtoMember(11)] public double ExternalWidth { get; set; }
        [ProtoMember(12)] public double FlangeWidth { get; set; }
        [ProtoMember(13)] public double FlangeThickness { get; set; }
        [ProtoMember(14)] public double WebWidth { get; set; }
    }
    

    以及序列化/反序列化:

    static void Main()
    {
        if (File.Exists("foo.bin")) File.Delete("foo.bin"); // start afresh
    
        Serialize(new Section { Diameter = 1.2, ClearCover = 3.4 }, "foo.bin");
        Serialize(new Section { Diameter = 5.6, ClearCover = 7.8 }, "foo.bin");
    
        var clone = DeserializeList("foo.bin");
    }
    static void Serialize(object obj, string filename)
    {
        using (FileStream streamOut = new FileStream(filename, FileMode.Append))
        {
            Serializer.NonGeneric.SerializeWithLengthPrefix(
                streamOut, obj, PrefixStyle.Base128, Serializer.ListItemTag);
        }
    }
    
    
    public static List<Section> DeserializeList(string filename)
    {
        using (FileStream streamIn = File.OpenRead(filename))
        {
            return Serializer.DeserializeItems<Section>(
                streamIn, PrefixStyle.Base128, Serializer.ListItemTag).ToList();
        }
    }
    

    最后,这两行的BinaryFormatter 数据是 750 字节;使用 protobuf-net:40 字节。

    【讨论】:

    • 对于第一部分(使用二进制格式化程序),它给了我这个错误 Unable to cast object of type 'System.Collections.Generic.List`1[KSU.Section]' to type 'KSU.部分'。这没有意义。根据您编写的代码,它不会将任何内容转换为 Section Type 对象
    • 我测试了一个9975行*4列的简单列表的最终格式,序列化和反序列化的时间很长,文件大小约为10GB(OMG)!
    • @SharifLotfi 大小通常是被序列化数据的真实反映;如果您认为 10GB 不正确,我很乐意更详细地了解您的方案
    • @MarcGravell 谢谢,我在我的代码中进行了审查,我发现了一个大错误,我在序列化函数中写了 listserialize(List&lt;obj&gt;,filename) 而不是serialize(new obj,filename),这是我的错误,抱歉,现在我的文件大小是 2MB ,但是序列化器需要很长时间(大约 01:15 分钟),并且反序列化非常快,这是我的类 obj:[ProtoContract] public class obj { [ProtoMember(1)] public string s1{ get; set; } [ProtoMember(2)] public string s2{ get; set; } [ProtoMember(3)] public string s3{ get; set; } [ProtoMember(4)] public double d1{ get; set; } }
    • @Sharif 我很乐意尝试并提供帮助,但要调查性能问题,我真的需要能够在本地重现它;那里真的没有足够的东西让我这样做。你有我可以复制的虚拟(或真实,如果不是 PII)数据/代码吗?也可能值得给我发电子邮件。
    猜你喜欢
    • 1970-01-01
    • 2014-01-04
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    • 1970-01-01
    • 1970-01-01
    • 2020-08-24
    • 2016-12-31
    相关资源
    最近更新 更多