XmlReader - Как прочитать очень длинную строку в элементе без System.OutOfMemoryException - PullRequest
0 голосов
/ 10 января 2019

Мне нужно прочитать содержимое файла Base64 строки в элементе XML, который возвращается из API.

Моя проблема в том, что эта строка может быть очень длинной, в зависимости от размера файла.

Сначала я использовал XmlDocument для чтения XML. Теперь я использую XmlReader, чтобы избежать System.OutOfMemoryException когда XML слишком велик.

Но я, когда читаю строку, тоже получаю System.OutOfMemoryException. Я думаю, что строка слишком длинная.

using (XmlReader reader = Response.ResponseXmlXmlReader)
{
    bool found = false;
    //Read result
    while (reader.Read() && !found)
    {
        if(reader.NodeType == XmlNodeType.Element && reader.Name == "content")
        {
            //Read file content
            string file_content = reader.ReadElementContentAsString();
            //Write file
            File.WriteAllBytes(savepath + file.name, Convert.FromBase64String(file_content));

            //Set Found!
            found = true;
        }
    }
} 

Как мне прочитать строку содержимого файла с XmlReader без System.OutOfMemoryException?

1 Ответ

0 голосов
/ 10 января 2019

Вы можете использовать XmlReader.ReadElementContentAsBase64(Byte[] buffer, Int32 index, Int32 count) для этой цели. Этот метод позволяет считывать и декодировать содержимое элемента Base64 элемента XML в виде фрагментов, что позволяет избежать OutOfMemoryException для больших элементов.

Например, вы можете ввести следующие методы расширения:

public static class XmlReaderExtensions
{
    public static bool ReadToAndCopyBase64ElementContentsToFile(this XmlReader reader, string localName, string namespaceURI, string path)
    {
        if (!reader.ReadToFollowing(localName, namespaceURI))
            return false;
        return reader.CopyBase64ElementContentsToFile(path);
    }

    public static bool CopyBase64ElementContentsToFile(this XmlReader reader, string path)
    {
        using (var stream = File.Create(path))
        {
            byte[] buffer = new byte[8192];
            int readBytes = 0;

            while ((readBytes = reader.ReadElementContentAsBase64(buffer, 0, buffer.Length)) > 0)
            {
                stream.Write(buffer, 0, readBytes);
            }
        }
        return true;
    }
}

А затем сделайте:

var path = Path.Combine(savepath, file.name);
var found = reader.ReadToAndCopyBase64ElementContentsToFile("content", "", path);

Демонстрационная скрипка здесь .

...