Friday, October 10, 2008

XML - Read/Write binary data (Base64)

XML is an industry standard for data transfer. Usually normal text is stored in XML, but it is possible to store any type of data in an XML file - songs, pictures, documents, executable files etc. Base64 encoding is used for doing this.

Functions listed below can be used for storing binary data in XML and retrieving it. In this example, the filename is also stored in the XML while saving, so that it can be used for retrieval (not mandatory; just application logic).

First, define a constant for the buffer size to be used.

private const int BUFFER_SIZE = 1024;

Code for writing binary data:

using System.IO;
using System.Xml;

private void WriteBase64Data(string sourceFile, string targetFile)
{
    try
    {
        byte[] data;

        using (FileStream fStream = new FileStream(sourceFile,
                                                                FileMode.Open,
                                                                FileAccess.Read))
        {
            // Read data and store it in the buffer
            using (BinaryReader reader = new BinaryReader(fStream))
            {
                data = reader.ReadBytes((int)fStream.Length);
                reader.Close();
            }
            fStream.Close();
        }

        using (MemoryStream memStream = new MemoryStream())
        {
            using (StreamReader reader = new StreamReader(memStream))
            {
                using (XmlTextWriter writer = new XmlTextWriter(memStream,
                                                                                System.Text.Encoding.UTF8))
                {
                    writer.WriteStartElement("BinaryData");

                    // Write the filename
                    writer.WriteStartElement("FileName");
                    writer.WriteValue(sourceFile.Substring(sourceFile.LastIndexOf('\\') + 1));
                    writer.WriteEndElement();

                    // Write actual data
                    writer.WriteStartElement("Data");
                    writer.WriteBase64(data, 0, data.Length);
                    writer.WriteEndElement();

                    writer.WriteEndElement();

                    writer.Flush();
                    memStream.Position = 0;

                    StringBuilder xmlData = new StringBuilder();
                    xmlData.Append(reader.ReadToEnd());

                    XmlDocument xDoc = new XmlDocument();
                    xDoc.LoadXml(xmlData.ToString());

                    // Save to disk
                    xDoc.Save(targetFile);

                    memStream.Close();
                }
            }
        }
    }
    catch
    {
        throw;
    }
}

Code for reading binary data from XML:

using System.IO;
using System.Xml;

private void ReadBase64Data(string sourceFile, string targetPath)
{
    try
    {
        XmlDocument xDoc = new XmlDocument();
        xDoc.Load(sourceFile);

        XmlNode fileName = xDoc.SelectSingleNode("BinaryData/FileName");
        XmlNode data = xDoc.SelectSingleNode("BinaryData/Data");

        // Set output directory
        string targetFile = targetPath;
        if (!targetFile.EndsWith(Path.DirectorySeparatorChar.ToString()))
            targetFile += Path.DirectorySeparatorChar;
        targetFile += fileName.InnerText;

        using (FileStream target = new FileStream(targetFile,
                                                                FileMode.Create,
                                                                FileAccess.ReadWrite,
                                                                FileShare.ReadWrite))
        {
            int bytesRead = 0;
            byte[] buffer = new byte[BUFFER_SIZE];

            using (BinaryWriter writer = new BinaryWriter(target))
            {
                StringReader sr = new StringReader(data.OuterXml);

                using (XmlTextReader reader = new XmlTextReader(sr))
                {
                    reader.MoveToContent();

                    // Read raw data and write to output stream
                    do
                    {
                        bytesRead = reader.ReadBase64(buffer, 0, BUFFER_SIZE);
                        writer.Write(buffer, 0, bytesRead);
                    }
                    while (bytesRead >= BUFFER_SIZE);
                }

                writer.Flush();
            }
        }
    }
    catch
    {
        throw;
    }
}

No comments: