Basically, I want to extract the stream from the XmlReader
and directly base64 decode it to a file.
The structure of the XML file can be seen here. To get the value I have to use ReadInnerXml()
. Is it possible to use ReadValueChunk
instead?
Here is my current code:
using (XmlReader reader = XmlReader.Create("/your/path/47311.xml"))
{
while(reader.Read())
{
if (reader.IsStartElement () && reader.NodeType == XmlNodeType.Element) {
switch (reader.Name) {
case "ttOutputRow":
reader.ReadToDescendant ("cKey");
switch (reader.ReadInnerXml ()) {
case "findMe":
reader.ReadToNextSibling ("cValue");
// here begins the interesting part
char[] buffer = new char[4096];
int charRead;
using (var destStream = File.OpenWrite ("/your/path/47311.jpg")) {
while ((charRead = reader.ReadValueChunk (buffer, 0, 4096)) != 0) {
byte[] decodedStream = System.Convert.FromBase64String (new string (buffer));
await destStream.WriteAsync(decodedStream, 0, decodedStream.Length);
Console.WriteLine ("in");
}
}
break;
default:
break;
}
break;
default:
break;
}
}
}
}
Currently, he doesn't read the value in.
Can't I use ReadValueChunk
for this? How can I directly use the stream from the XmlReader
without sacrificing too much memory?
Edit:
According to dbc I modified my code. This is what I currently use:
using (XmlReader reader = XmlReader.Create("test.xml"))
{
while(reader.Read())
{
if (reader.IsStartElement () && reader.NodeType == XmlNodeType.Element) {
switch (reader.Name) {
case "ttOutputRow":
reader.ReadToDescendant ("cKey");
switch (reader.ReadInnerXml ()) {
case "findMe":
reader.ReadToNextSibling ("cValue");
byte[] buffer = new byte[40960];
int readBytes = 0;
using (FileStream outputFile = File.OpenWrite ("test.jpg"))
using (BinaryWriter bw = new BinaryWriter(outputFile))
{
while ((readBytes = reader.ReadElementContentAsBase64(buffer, 0, 40960)) > 0) {
bw.Write (buffer, 0, readBytes);
Console.WriteLine ("in");
}
}
break;
default:
break;
}
break;
default:
break;
}
}
}
}
Here you can find a test file. The real file is a little bit bigger and therefore takes much more time.
The above code doesn't work as expected. It is very slow and the extracted image is mostly black (destroyed).
In order to give a definitive answer to your question I would need to see the XML you are trying to read. However, two points:
According to the documentation for Convert.FromBase64String
:
The FromBase64String method is designed to process a single string that contains all the data to be decoded. To decode base-64 character data from a stream, use the System.Security.Cryptography.FromBase64Transform class.
Thus your problem may be with decoding the content in chunks rather than with reading it in chunks.
You can use XmlReader.ReadElementContentAsBase64
or XmlReader.ReadElementContentAsBase64Async
for exactly this purpose. From the docs:
This method reads the element content, decodes it using Base64 encoding, and returns the decoded binary bytes (for example, an inline Base64-encoded GIF image) into the buffer.
In fact, the example in the documentation demonstrates how to extract a base64-encoded image from an XML file and write it to a binary file in chunks.