有没有办法在C#中保存和加载复杂的数据结构到二进制文件?

问题描述 投票:0回答:1

问题

我正在用 C# 编写一个程序,用于保存和加载特定结构中的对象列表,如下所示:

SIGNATURE\r\n
SIZE\r\n
OBJECT_DATA\r\n
\r\n
SIZE\r\n
OBJECT_DATA\r\n
\r\n

Signature
是一个原始字符串,其中包含私钥,用于将我的数据文件与其他文件分开。

SIZE
是一个整数值,表示
OBJECT_DATA
使用的字节数。

OBJECT_DATA
是一个包含我的数据的类。

我尝试过的事情

我在 Stackoverflow 中找到了很多解决方案,几乎所有解决方案都使用

BinaryFormatter
,这是不安全的,不应该使用。

我还查看了protobuf-net,但我仍然很困惑如何将其应用于我的问题。

我的想法

我认为解决方案的序列化和反序列化阶段将如下所示:

序列化(假设输入/输出文件是二进制文件):

1. Open output file and write the signature.
2. Loop over the source object list
    - With each item, calculate the size of item and write it to output file.
    - Write object data to binary file. (I'm still confusing in this step)
    - Write "\r\n" to mark this is the end of the item.

反序列化

1. Open input file and read the Signature
2. If the Signature fit with my secret key:
    - Loop until end of file
        - Read the SIZE value.
        - Read object and create instance of it's class.

更新

我提到的

OBJECT_DATA
是一个类的实例:

public abstract class IShape
{
    public State Configuration { get; set; }
    public abstract string Name { get; }
    public List<Point> Points { get; set; } = [];
    public abstract UIElement Draw();
    public abstract IShape Clone();
    public BitmapImage Preview { get; set; }
}

State Configuration
的结构:

public class State
{
    public DoubleCollection StrokeDashArray { get; set; }
    public SolidColorBrush Stroke { get; set; }
    public SolidColorBrush Fill { get; set; }
    public double StrokeThickness { get; set; }
}

我认为 Protobuf-net 是将对象序列化为

Stream
的好方法,但我的类包含
System.Windows.Media
中的一些值,我不确定是否可以使用 Protobuf-net 对其进行序列化。

c# file serialization binary deserialization
1个回答
0
投票

我通过将

IShape
State
组合到 POCO 类中来解决我自己的问题。

public class ShapeProtocol
{
    public string Name { get; set; }
    public string StartX { get; set; }
    public string StartY { get; set; }
    public string EndX { get; set; }
    public string EndY { get; set; }
    public string StrokeThickness { get; set; }
    public string Stroke { get; set; }
    public string? StrokeDashArray { get; set; }
    public string? Fill { get; set; }

    public ShapeProtocol() { }

    public ShapeProtocol(IShape shape)
    { /* Constructor */ }

    public static IShape ConvertBack(ShapeProtocol protocol)
    { /*...*/ }
}

然后我实现了一个

ShapeSerializer

public static class ShapeSerializer
{
    public static string Serialize(IShape shape)
    {
        var shapeProtocol = new ShapeProtocol(shape);

        var properties = from p in shapeProtocol.GetType().GetProperties()
                         where p.GetValue(shapeProtocol, null) != null
                         select p.Name + "=" + p.GetValue(shapeProtocol, null);

        // this string will be the OBJECT_DATA I mentioned. 
        // the result will look like this: Name=Ellipse;StartX=240;StartY=48.2;EndX=411.3;EndY=140;StrokeThickness=1;Stroke=#FFDC143C
        return String.Join(";", properties.ToArray());
    }

    public static IShape Deserialize(string rawData)
    {
        var _raw = rawData.Split(';').ToDictionary(p => p.Split("=")[0], p => p.Split("=")[1]);
        var deserialized = new ShapeProtocol();

        var _properties = typeof(ShapeProtocol).GetProperties();
        foreach (var property in _properties)
        {
            try
            {
                var value = _raw[property.Name];
                property.SetValue(deserialized, value, null);
            }
            catch { /* assume that value is null */ }
        }

        return ShapeProtocol.ConvertBack(deserialized);
    }
}

然后我只是使用

FileStream
来存储/加载具有文件结构的数据,这是这个问题的最开始。

向@JonSkeet 和@MarcGravell 表示感谢。你们俩都是解决这个问题的重要灵感来源。

© www.soinside.com 2019 - 2024. All rights reserved.