2009-11-07 32 views
1

我有一些類型的序列化數組。 有沒有一種方法,而不需要讀取已經保存收集到內存中追加新的對象,這個序列化陣列(以序列化的形式)?追加到序列化集合

實施例:

我在file.xml具有,實體的XML序列化陣列含有10^12個元件。我需要另一個10^5元素添加到序列化的文件,但我不想讀了之前所有的,追加新的譜寫新的陣列流,因爲這將是非常耗費資源(尤其是內存) 。

它如果它需要一個二進制串行器,我會沒有問題。

+1

這個問題是一個大雜燴。什麼是「XML序列化數組」?只是一個帶有根元素的XML文件,然後是很多子元素而沒有其他層次結構?這個問題完全取決於數據的結構,關於它的詳細信息很少。 – mquander

+0

一個使用IFormatter.Serialize()序列化的類的數組。實際上,串行器的類型並不重要。出於性能原因,我可能會稍後使用二進制文件。 –

回答

7

一般來說,解決方案是更改XML字節,這樣您不必在反序列化中讀取所有內容。

一般的步驟是:

  1. 列表項
  2. 打開文件流
  3. 存儲陣列的收盤點
  4. 序列化新項目
  5. 寫連載字節流
  6. 編寫關閉節點

代碼例如,一個整數添加到序列化的陣列:

// Serialize array - in you case it the stream you read from file.xml 
var ints = new[] { 1, 2, 3 }; 
var arraySerializer = new XmlSerializer(typeof(int[])); 
var memoryStream = new MemoryStream(); // File.OpenWrite("file.xml") 
arraySerializer.Serialize(new StreamWriter(memoryStream), ints); 

// Save the closing node 
int sizeOfClosingNode = 13; // In this case: "</ArrayOfInt>".Length 
          // Change the size to fit your array 
          // e.g. ("</ArrayOfOtherType>".Length) 

// Set the location just before the closing tag 
memoryStream.Position = memoryStream.Length - sizeOfClosingNode; 

// Store the closing tag bytes 
var buffer = new byte[sizeOfClosingNode]; 
memoryStream.Read(buffer, 0, sizeOfClosingNode); 

// Set back to location just before the closing tag. 
// In this location the new item will be written. 
memoryStream.Position = memoryStream.Length - sizeOfClosingNode; 

// Add to serialized array an item 
var itemBuilder = new StringBuilder(); 
// Write the serialized item as string to itemBuilder 
new XmlSerializer(typeof(int)).Serialize(new StringWriter(itemBuilder), 4); 
// Get the serialized item XML element (strip the XML document declaration) 
XElement newXmlItem = XElement.Parse(itemBuilder.ToString()); 
// Convert the XML to bytes can be written to the file 
byte[] bytes = Encoding.Default.GetBytes(newXmlItem.ToString()); 
// Write new item to file. 
memoryStream.Write(bytes, 0, bytes.Length); 
// Write the closing tag. 
memoryStream.Write(buffer, 0, sizeOfClosingNode); 

// Example that it works 
memoryStream.Position = 0; 
var modifiedArray = (int[]) arraySerializer.Deserialize(memoryStream); 
CollectionAssert.AreEqual(new[] { 1, 2, 3, 4 }, modifiedArray); 
+0

嗨,以利沙,這似乎是一個非常有趣的答案,我已經投了票。對於像我這樣的人沒有這方面的很多經驗,這將是有益的,如果你能在你的代碼添加一些新的意見:例如,在不上面使用的值#13來自(它是基於你的知識究竟有多少個字節將int的數組{1,2,3}寫入到內存流中?)。另一個問題:你的例子顯示了對內存流的修改(你將文件寫爲XML註釋掉了):可以用沒有主要mod的內存流代替嗎?謝謝, – BillW

+0

@BillW,增加了一些評論,它不是直觀的代碼,所以我希望它可以幫助:) #13的編號會根據序列化的類型而改變。它表示關閉數組XML的節點名稱長度。例如將佔用16個字節(每個字符的字節數)。 我用的MemoryStream只是爲了回答可讀性和清晰的(我想我是不是太成功),但它的股票相同的基本使用FileStream。兩者都是流,將實際生活中的第一個塊替換爲File.OpenWrite(「file.xml」)不會影響負責添加新項目的其餘代碼。 – Elisha