我想将一个数组模型对象序列化为二进制流。模型类主要有字符串和整数属性。
我相信我可以将该类标记为[Serializable]并使用二进制格式化程序,但是我有兴趣知道您是否认为这是最好的方法,请记住我的优先级是让文件小到可以通过低带宽连接进行传输(我也可以压缩/解压缩文件)。
该文件可能有1000条记录,所以理想情况下我希望能够附加到磁盘并按记录读取磁盘记录,而不必一次将整个文件放在内存中。
所以我的优先事项是:文件小,内存使用效率高。
也许有预先编写的框架?使用XML和CSV文件似乎很容易!希望它也是一种自定义二进制格式。
感谢
答案 0 :(得分:6)
我建议protobuf.net非常有效。
话虽如此,这将无法处理您的集合中的单个对象的序列化/解除序列。那部分你需要自己实现。
一种解决方案是:将对象存储为文件夹中的单个文件。文件名将包含一个引用,以便根据名称,您可以找到所需的对象。
另一个是拥有一个文件,但保留一个索引文件,该文件保存所有对象及其在文件中的位置的列表。这要复杂得多,因为当您保存位于文件中间的对象时,您必须移动所有其他地址,并且b树可能更有效。
答案 1 :(得分:2)
另一个选择是序列化为固定宽度的文本文件格式,让ZIP处理压缩。固定宽度意味着您可以轻松使用MemoryMappedFile遍历每条记录,而无需将整个文件加载到内存中。
答案 2 :(得分:1)
您可以使用BinaryFormatter。这是一个很好的解决方案,想要一个小文件,但只有你知道它是否是你的域的最佳解决方案。不过,我认为你不能一次阅读一条记录。
我目前唯一的示例代码是DataSet。这些扩展方法将(de)序列化自定义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&amp; Albahari)。在这种情况下,您还需要阅读Best Practices: Data Contract Versioning。下面是如何(de)序列化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);
}
答案 3 :(得分:1)
我建议使用Sql Server Compact将对象存储为对象而不进行序列化,它非常轻量级且速度极快,我在高负载下使用它来为服务器上的大量请求提供服务。
我也不建议以二进制格式存储数据(序列化),因为在更改要存储的对象时会非常痛苦。如果你必须看到你正在存储的内容,那也很痛苦,因为你必须反序列化整个集合。
至于发送,如果需要,我更喜欢使用带有zip压缩的XML序列化。如果您需要查看发送的内容或进行一些测试,XML格式可以使调试变得更加容易。
答案 4 :(得分:0)
如果你想让它变小,你自己动手吧。确保只存储您需要的数据。例如,如果只有255个不同的值,则使用一个字节。
http://msdn.microsoft.com/en-us/library/system.bitconverter.aspx
我几乎总是使用这样的简单结构来存储数据
id(ushort)
data_size(uint)
数据大小data_size
只存储您必须拥有的信息,不要考虑如何使用它。当您加载它时,您会考虑如何使用数据。
答案 5 :(得分:0)
我很想坚持使用BinaryFormatter作为对象本身,或者像其他地方建议的那样使用protobuf.net。
如果随机访问方面非常重要(按记录阅读和追加记录),您可能需要查看创建包含索引文件的zip文件(或类似文件),并将每个对象序列化为zip文件中的自己文件(或者也许是小集合)。
这样,您就可以有效地拥有一个压缩的迷你文件系统,并让您可以单独访问您的记录。