简体   繁体   中英

XmlReader - How to read very long string in element without System.OutOfMemoryException

I have to read a file content Base64 string in an element of XML that is returned from an API.

My problem is this string can be very long, depending on file size.

At first, I used XmlDocument to read XML. Now I use XmlReader to avoid System.OutOfMemoryException when XML is too large.

But I when I read the string, receive a System.OutOfMemoryException too. The string is too long, I guess.

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;
        }
    }
} 

How can I read file content string with XmlReader without System.OutOfMemoryException ?

You can use XmlReader.ReadElementContentAsBase64(Byte[] buffer, Int32 index, Int32 count) for this purpose. This method allows for Base64 element contents of an XML element to be read and decoded in chunks, thus avoiding an OutOfMemoryException for large elements.

For instance, you could introduce the following extension methods:

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;
    }
}

And then do:

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

Demo fiddle here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM