5

我想让一个数组模型对象序列化为二进制流。模型类将主要具有字符串和整数属性。

我相信我可以将类标记为 [Serializable] 并使用二进制格式化程序,但是我很想知道您是否认为这是最好的方法,请记住我的首要任务是传输尽可能小的文件通过低带宽连接(我也可以压缩/解压缩文件)。

该文件可能有 1000 条记录,因此理想情况下,我希望能够逐条记录地附加到磁盘并从磁盘读取,而不必一次将整个文件放在内存中。

所以我的优先事项是:小文件大小和有效的内存使用。

也许有一个预先编写的框架?使用 XML 和 CSV 文件似乎很容易!希望它也具有自定义二进制格式。

谢谢

4

6 回答 6

6

我建议使用非常有效的protobuf.net 。

话虽如此,这将无法处理集合中的单个对象的序列化/反序列化。那部分你需要自己实现。

  • 一种解决方案是: 将对象作为单个文件存储在文件夹中。文件名将包含一个引用,以便根据名称,您可以找到所需的对象。

  • 另一种方法是拥有一个文件,但保留一个索引文件,该文件保留所有对象的列表及其在文件中的位置。这要复杂得多,因为当您保存文件中间的对象时,您必须移动所有其他地址,也许 b-tree 更有效。

于 2011-03-18T15:36:34.470 回答
2

Another option is to just serialize to a fixed-width text file format and let ZIP handle the compression. Fixed-width means you can easily use a MemoryMappedFile to walk through each record without needing to load the entire file into memory.

于 2011-03-18T15:43:06.480 回答
1

您可以使用BinaryFormatter。对于想要一个小文件来说,这是一个很好的解决方案,但只有您知道它是否是您的域的最佳解决方案。不过,我不认为你可以一次读一张唱片。

我目前唯一的示例代码是DataSet。这些扩展方法将(反)序列化自定义数据集,如果我没记错的话,这是拥有可以使用 BinaryFormatter 的类型的最简单方法。

public static TDataSet LoadBinary<TDataSet>(Stream stream) where TDataSet : DataSet
{
    var formatter = new BinaryFormatter();
    return (TDataSet)formatter.Deserialize(stream);
}

public static void WriteBinary<TDataSet>(this TDataSet dataSet, Stream stream) where TDataSet : DataSet
{
    dataSet.RemotingFormat = SerializationFormat.Binary;
    var formatter = new BinaryFormatter();
    formatter.Serialize(stream, dataSet);
}

您还可以查看DataContractSerializer,这是 .NET 处理序列化的新“标准”方式(根据 C# 4.0 In A Nutshell, Albahari & Albahari)。在这种情况下,您还需要阅读最佳实践:数据合同版本控制。以下是如何在 XML 和 JSON 中(反)序列化的示例,即使它们不会直接适用于您的情况(因为您需要小文件)。但是你可以压缩文件。

/// <summary>
/// Converts this instance to XML using the <see cref="DataContractSerializer"/>.
/// </summary>
/// <typeparam name="TSerializable">
/// A type that is serializable using the <see cref="DataContractSerializer"/>.
/// </typeparam>
/// <param name="value">
/// The object to be serialized to XML.
/// </param>
/// <returns>
/// Formatted XML representing this instance. Does not include the XML declaration.
/// </returns>
public static string ToXml<TSerializable>(this TSerializable value)
{
    var serializer = new DataContractSerializer(typeof(TSerializable));
    var output = new StringWriter();
    using (var writer = new XmlTextWriter(output) { Formatting = Formatting.Indented })
    {
        serializer.WriteObject(writer, value);
    }
    return output.GetStringBuilder().ToString();
}

/// <summary>
/// Converts this instance to XML using the <see cref="DataContractSerializer"/> and writes it to the specified file.
/// </summary>
/// <typeparam name="TSerializable">
/// A type that is serializable using the <see cref="DataContractSerializer"/>.
/// </typeparam>
/// <param name="value">
/// The object to be serialized to XML.
/// </param>
/// <param name="filePath">Path of the file to write to.</param>
public static void WriteXml<TSerializable>(this TSerializable value, string filePath)
{
    var serializer = new DataContractSerializer(typeof(TSerializable));
    using (var writer = XmlWriter.Create(filePath, new XmlWriterSettings { Indent = true }))
    {
        serializer.WriteObject(writer, value);
    }
}

/// <summary>
/// Creates from an instance of the specified class from XML.
/// </summary>
/// <typeparam name="TSerializable">The type of the serializable object.</typeparam>
/// <param name="xml">The XML representation of the instance.</param>
/// <returns>An instance created from the XML input.</returns>
public static TSerializable CreateFromXml<TSerializable>(string xml)
{
    var serializer = new DataContractSerializer(typeof(TSerializable));

    using (var stringReader = new StringReader(xml))
    using (var reader = XmlReader.Create(stringReader))
    {
        return (TSerializable)serializer.ReadObject(reader);
    }
}

/// <summary>
/// Creates from an instance of the specified class from the specified XML file.
/// </summary>
/// <param name="filePath">
/// Path to the XML file.
/// </param>
/// <typeparam name="TSerializable">
/// The type of the serializable object.
/// </typeparam>
/// <returns>
/// An instance created from the XML input.
/// </returns>
public static TSerializable CreateFromXmlFile<TSerializable>(string filePath)
{
    var serializer = new DataContractSerializer(typeof(TSerializable));

    using (var reader = XmlReader.Create(filePath))
    {
        return (TSerializable)serializer.ReadObject(reader);
    }
}

public static T LoadJson<T>(Stream stream) where T : class
{
    var serializer = new DataContractJsonSerializer(typeof(T));
    object readObject = serializer.ReadObject(stream);
    return (T)readObject;
}

public static void WriteJson<T>(this T value, Stream stream) where T : class
{
    var serializer = new DataContractJsonSerializer(typeof(T));
    serializer.WriteObject(stream, value);
}
于 2011-03-18T15:34:34.647 回答
1

我建议使用 Sql Server Compact 将对象存储为对象而不进行序列化,它非常轻量级且速度极快,我在高负载下使用它来为服务器上的大量请求提供服务。

我也不建议以二进制格式(序列化)存储数据,因为在更改要存储的对象时会非常痛苦。如果您必须查看存储的内容也很痛苦,因为您必须反序列化整个集合。

至于发送,我更喜欢在必要时使用带有 zip 压缩的 XML 序列化。如果您需要查看发送的内容或进行一些测试,XML 格式会使调试变得更加容易。

于 2011-03-18T15:38:00.460 回答
0

如果你想让它变小,你自己做。确保只存储您需要的数据。例如,如果您只有 255 个不同的值,则使用一个字节。

http://msdn.microsoft.com/en-us/library/system.bitconverter.aspx

我几乎总是使用像这样的简单结构来存储数据

id (ushort)

数据大小(单位)

大小数据 data_size

只存储您必须拥有的信息,不要考虑如何使用它。当您加载它时,您会考虑如何使用数据。

于 2011-03-18T15:39:00.470 回答
0

我很想坚持使用 BinaryFormatter 作为对象本身,或者可能是 protobuf.net,如其他地方所建议的那样。

如果这方面的随机访问非常重要(逐条读取和附加记录),您可能希望查看创建一个包含索引文件的 zip 文件(或类似文件),并且每个对象都序列化为 zip 中自己的文件(或者可能在小型收藏中)。

这样,您可以有效地拥有一个经过压缩的迷你文件系统,让您可以单独访问您的记录。

于 2011-03-18T15:39:19.237 回答