附加到序列化集合

时间:2009-11-07 00:17:24

标签: c# optimization memory serialization

我正在使用某种类型的序列化数组。 有没有办法将新对象附加到此序列化数组(以序列化形式),而无需将已保存的集合读入内存?

示例:

我在一个file.xml中,包含10 ^ 12个元素的实体的XML序列化数组。我需要在序列化文件中添加另外10 ^ 5个元素,但是我不想读取所有以前的元素,添加新的元素并将新数组写入流,因为它会占用大量资源(特别是内存)

如果它需要二进制序列化器,我就没问题了。

1 个答案:

答案 0 :(得分:7)

一般来说,解决方案是更改XML字节,这样就不必像反序列化一样阅读所有内容。

一般步骤如下:

  1. 列表项
  2. 打开文件流
  3. 存储数组的结束节点
  4. 序列化新项目
  5. 将序列化字节写入流
  6. 编写结束节点
  7. 例如,为序列化数组添加整数的代码:

    // 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);