2011-03-18 78 views
5

我想將一個數組模型對象序列化爲二進制流。模型類將主要具有字符串和整數屬性。在C中有1000個記錄的二進制文件格式#

我相信,我可以將類標記爲[Serializable接口]並使用二進制formattter,但是我很想知道你是否認爲這是心目中最好的方式軸承,我的首要任務是有較小的文件儘可能通過低帶寬連接傳輸(我也可以壓縮/解壓文件)。

該文件可能有1000個記錄,所以理想情況下我希望能夠附加到磁盤並通過記錄從磁盤記錄讀取,而不必一次將整個文件存儲在內存中。

所以我的優先事項是:小文件大小和高效的內存使用。

也許有一個預先編寫的框架?使用XML和CSV文件似乎很容易!希望它也是一種自定義的二進制格式。

感謝

回答

6

我建議protobuf.net這是非常有效的。

話雖如此,這將無法處理您的集合中的序列化/取消個別對象。你需要實現自己的那部分。

  • 一種解決方案是:將對象作爲單個文件存儲在文件夾中。文件名將包含一個引用,以便根據名稱找到所需的對象。

  • 另一個是有一個文件,但保留一個索引文件,該文件保存文件中所有對象及其位置的列表。當你保存一個位於文件中間的對象時,這將變得更加複雜,你必須移動所有其他地址,並且也許一棵B樹更有效。

+2

對於第二個選項:[FileDB](http://nuget.org/List/Packages/FileDB)。 – 2011-03-18 15:47:41

+0

謝謝Martinho。我喜歡FileDB! – Aliostad 2011-03-18 16:01:22

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簡而言之,阿爾巴哈利&阿爾巴哈利)。在這種情況下,您還需要閱讀Best Practices: Data Contract Versioning。下面是如何以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); 
} 
1

我會建議使用的SQL Server Compact來存儲你的對象爲對象序列化無,這是相當輕巧,速度極快,我服了很多服務器的請求用它在高負載。

我也不建議以二進制格式(序列化)存儲數據,因爲當涉及到更改要存儲的對象時,這將是一個極大的痛苦。如果你必須看到你存儲的內容,這也是很痛苦的,因爲你必須對整個集合進行反序列化。

至於發送,如果需要的話,我更喜歡使用帶zip壓縮的XML序列化。如果您需要查看您發送的內容或進行一些測試,XML格式使調試變得更加容易。

0

如果你想讓它變小,請自己動手。確保只存儲您需要的數據。例如,如果只有255個不同的值,則使用一個字節。

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

我幾乎總是使用這樣簡單的結構來存儲數據

ID(USHORT)

DATA_SIZE(UINT)大小DATA_SIZE的

數據

只存儲您必須擁有的信息,不要考慮它將如何使用。當你加載它時,你會考慮如何使用這些數據。

0

我會試圖堅持BinaryFormatter的對象本身,或者也許protobuf.net建議其他地方。

如果隨機訪問方面非常重要(按記錄讀取和附加記錄),您可能需要查看創建包含索引文件的zip文件(或類似文件),並將每個對象序列化爲其自己的文件拉鍊(或者可能在小集合中)。

通過這種方式,您可以有效地使用壓縮的迷你文件系統,並且可以單獨訪問您的記錄。

2

另一種選擇是將序列化爲固定寬度的文本文件格式,並讓ZIP處理壓縮。固定寬度意味着您可以輕鬆使用MemoryMappedFile來遍歷每條記錄,而無需將整個文件加載到內存中。