Convert varbinary to xml c #

I have a C # winforms Application that stores files in sqlserver Database (2014) in a varbinary field (MAX)

Function To save

 byte[] Bytefile;
        using (SqlConnection conn = new SqlConnection(DataHelper.GetConnection()))
        {
            conn.Open();
            DataTable dt = new DataTable();
            SqlCommand comm = new SqlCommand("Delete  T_Articale_Files where Artricle_id=" + ID, conn);

            comm.ExecuteNonQuery();
            foreach (string file in Directory.GetFiles(varFilePath))
            {

                using (var stream = new FileStream(Path.Combine(varFilePath, file), FileMode.Open, FileAccess.Read))
                {
                    using (var reader = new BinaryReader(stream))
                    {
                        Bytefile = reader.ReadBytes((int)stream.Length);
                    }
                }


                using (var sqlWrite = new SqlCommand("INSERT INTO T_Articale_Files (Artricle_id,FileName,FileData) Values(@ID,@FileName,@File)", conn))
                {
                    sqlWrite.Parameters.Add("@ID", SqlDbType.Int, 10).Value = ID;
                    sqlWrite.Parameters.Add("@FileName", SqlDbType.NVarChar, 50).Value = Path.GetFileName(file);
                    sqlWrite.Parameters.Add("@File", SqlDbType.VarBinary, file.Length).Value = Bytefile;
                    sqlWrite.ExecuteNonQuery();
                }
            }
        }

      

Function to extract

 using (SqlConnection conn = new SqlConnection(DataHelper.GetConnection()))
        //   using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
        {
            conn.Open();
            DataTable dt = new DataTable();
            SqlCommand comm = new SqlCommand("SELECT id,FileName FROM T_Articale_Files WHERE Artricle_id = @varID", conn);
            comm.Parameters.AddWithValue("@varID", varID);
            dt.Load(comm.ExecuteReader());
            foreach (DataRow item in dt.Rows)
            {
                using (var sqlQuery = new SqlCommand(@"SELECT FileData FROM T_Articale_Files WHERE id = @ID", conn))
                {
                    sqlQuery.Parameters.AddWithValue("@ID", item["id"]);

                    using (var sqlQueryResult = sqlQuery.ExecuteReader())
                        while (sqlQueryResult.Read())
                        {

                            var blob = new Byte[(sqlQueryResult.GetBytes(0, 0, null, 0, int.MaxValue))];
                            sqlQueryResult.GetBytes(0, 0, blob, 0, blob.Length);
                            using (var fs = new FileStream(Path.Combine(varPathToNewLocation, item["FileName"].ToString()), FileMode.Create, FileAccess.Write))
                                fs.Write(blob, 0, blob.Length);
                        }
                }
            }

        }

      

which work fine Now I have asked to convert the database to XML for PCs that have no server connection

XML conversion function

 var xmlFileData = "";
        DataSet ds = new DataSet();
        var tables = new[] { "V_Articale", "T_Articale", "T_City", "T_Classification", "T_Country", "T_Locations", "T_milishia", "T_Search", "T_statistics", "T_TerrorGroups", "T_Tribes", "T_Users", "T_Articale_Files" };
        foreach (var table in tables)
        {

            var query = "SELECT * FROM " + table;
            SqlConnection conn = GetConnection();
            SqlCommand cmd = new SqlCommand(query, conn);
            conn.Open();
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataTable dt = new DataTable(table);
            da.Fill(dt);
            conn.Close();
            conn.Dispose();
            ds.Tables.Add(dt);
            if(table== "T_Articale_Files")
            {
                foreach (DataRow item in dt.Rows)
                {
                    Byte[] file = GetBytes(item["FileData"].ToString());
                }
            }

        }
        xmlFileData = ds.GetXml();

      

works fine except for binary notation it is converted to text when

Output XML

<T_Articale_Files>
<id>6</id>
<Artricle_id>1013</Artricle_id>
<FileName>falcon banner.jpg</FileName>
<FileData>/9j/4AAQSkZJRgABAgEASABIAAD/4QleRXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUA</FileData>

      

when you try to convert it back to image it gives me a 1kb file with a string and not an actual image

there is a special converter for binary field Advise

thank

Change the problem. Solved thanks to @ grek40 Solution Convert to XML

  var xmlstream = new StringWriter();
        ds.WriteXml(xmlstream, XmlWriteMode.WriteSchema);
        string xmlWithSchema = xmlstream.ToString();

      

where ds is the dataset

Convert back to file

  private  void databaseFileRead(int varID, string varPathToNewLocation)
    {
         DataSet ds = new DataSet();
        ds.ReadXml(XMLpath);
        DataTable dt = new DataTable();
        dt = ds.Tables["T_Articale_Files"];
        DataView dv = new DataView(dt);
        dv.RowFilter = "Artricle_id=" + varID;

        if (dv.Count > 0)
        {
            foreach (DataRowView item in dv)
            {
                byte[] stringArray = (byte[])(item["FileData"]);
                File.WriteAllBytes(Path.Combine(Filepath, item["FileName"].ToString()), stringArray  ); // save image to disk


            }

        }

      

+3


source to share


2 answers


To have reversible string encoding of binary data you can use Base64 encoding

public byte[] StrToByteArray(string str)
{
    return Convert.FromBase64String(str);
}

public string ByteArrToString(byte[] byteArr)
{
    return Convert.ToBase64String(byteArr);
}

      

convert bytes to string which is stored in xml and recover bytes from string when used.

Initially, the data is correctly written as xml. The problem is most likely with the extract function. Since the xml contains no schema information, it will treat text <FileData>

as text unless instructed otherwise.



To ensure correct re-reads, you either need a preset schema when reading, or you need to write a schema with tables:

dataSet.WriteXml(filenameOrStream, XmlWriteMode.WriteSchema)
// later read the xml and it will respect the schema information
dataSet.ReadXml(filenameOrStream);

      

A small selection of different aspects:

var sourceDataSet = new DataSet();
var sourceTable = new DataTable("TableWithBinary");

sourceDataSet.Tables.Add(sourceTable);

sourceTable.Columns.Add("Id");
sourceTable.Columns.Add("File", typeof(byte[]));

sourceTable.Rows.Add(1, new byte[] { 1, 0, 2 });
sourceTable.Rows.Add(2, new byte[] { 1, 3, 2 });

// write option 1
string schema = sourceDataSet.GetXmlSchema();
string getxml = sourceDataSet.GetXml();

// write option 2
var writexmlstream = new StringWriter();
sourceDataSet.WriteXml(writexmlstream, XmlWriteMode.WriteSchema);
string writexmlWithSchema = writexmlstream.ToString();

// read wrong (missing schema)
var targetCorrupted = new DataSet();
targetCorrupted.ReadXml(new StringReader(getxml));

// read correct with schema in every xml file
var targetFromXmlWithSchema = new DataSet();
targetFromXmlWithSchema.ReadXml(new StringReader(writexmlWithSchema));

// read correct with separate schema definition and data
var targetFromXml = new DataSet();
targetFromXml.ReadXmlSchema(new StringReader(schema));
targetFromXml.ReadXml(new StringReader(getxml));

      

+2


source


The standard format for binary code in XML is base64

. I don't think there is anything wrong with that ...

You must remember that multiple characters are prohibited in XML. You cannot just write binary data between two XML tags. If there was a numeric code for <

(or some other forbidden character) somewhere in your binary it would break.

The line you are showing is very similar to the base64 code.

try it

DECLARE @string VARCHAR(100)='Hello World with forbidden characters (< & >)';
DECLARE @binary VARBINARY(MAX) = CAST(@string AS VARBINARY(MAX));
DECLARE @xml XML=(SELECT @string AS string, @binary AS bin FOR XML PATH('test'));

SELECT @xml;

      

- Result (with encoded entities and binary implicitly converted to base64)



<test>
  <string>Hello World with forbidden characters (&lt; &amp; &gt;)</string>
  <bin>SGVsbG8gV29ybGQgd2l0aCBmb3JiaWRkZW4gY2hhcmFjdGVycyAoPCAmID4p</bin>
</test>

      

- We are now reading from XML (objects are recoded, binary is represented as a HEX string and this can be re-appended to the previous one VARCHAR(MAX)

SELECT @xml.value('(/test/string)[1]','nvarchar(max)') AS TheStringAsIs
      ,@xml.value('(/test/bin)[1]','varbinary(max)') AS TheStringAsBinary_HEX
      ,CAST(@xml.value('(/test/bin)[1]','varbinary(max)') AS VARCHAR(100)) AS ReConverted

      

results

The string *as-is*:  Hello World with forbidden characters (< & >)  
binary data HEX:     0x48656C6C6F20576F726C64207769746820666F7262696464656E206368617261637465727320283C2026203E29   
ReConverted:         Hello World with forbidden characters (< & >) 

      

0


source







All Articles