/// <summary> /// sql二进制结构翻译,这个比较关键,测试环境为sql2005,其他版本没有测过。 /// </summary> /// <param name="data"></param> /// <param name="columns"></param> static void TranslateData(byte[] data, Datacolumn[] columns) { //我只根据示例写了Char,DateTime,Int三种定长度字段和varchar一种不定长字段,其余的有兴趣可以自己补充 //这里没有暂时没有考虑Null和空字符串两种情况,以后会补充。 //引用请保留以下信息: //作者:jinjazz //sql的数据行二进制结构参考我的blog //http://blog.csdn.net/jinjazz/archive/2008/08/07/2783872.aspx //行数据从第5个字节开始 short index = 4; //先取定长字段 foreach (Datacolumn c in columns) { switch (c.DataType) { case System.Data.SqlDbType.Char: //读取定长字符串,需要根据表结构指定长度 c.Value = System.Text.Encoding.Default.GetString(data, index, c.Length); index += c.Length; break; case System.Data.SqlDbType.DateTime: //读取datetime字段,sql为8字节保存 System.DateTime date = new DateTime(1900, 1, 1); //前四位1/300秒保存 int second = BitConverter.ToInt32(data, index); date = date.AddSeconds(second / 300); index += 4; //后四位1900-1-1的天数 int days = BitConverter.ToInt32(data, index); date = date.AddDays(days); index += 4; c.Value = date; break; case System.Data.SqlDbType.Int: //读取int字段,为4个字节保存 c.Value = BitConverter.ToInt32(data, index); index += 4; break; default: //忽略不定长字段和其他不支持以及不愿意考虑的字段 break; } } //跳过三个字节 index += 3; //取变长字段的数量,保存两个字节 short varColumnCount = BitConverter.ToInt16(data, index); index += 2; //接下来,每两个字节保存一个变长字段的结束位置, //所以第一个变长字段的开始位置可以算出来 short startIndex = (short)(index + varColumnCount * 2); //第一个变长字段的结束位置也可以算出来 short endIndex = BitConverter.ToInt16(data, index); //循环变长字段列表读取数据 foreach (Datacolumn c in columns) { switch (c.DataType) { case System.Data.SqlDbType.VarChar: //根据开始和结束位置,可以算出来每个变长字段的值 c.Value = System.Text.Encoding.Default.GetString(data, startIndex, endIndex - startIndex); //下一个变长字段的开始位置 startIndex = endIndex; //获取下一个变长字段的结束位置 index += 2; endIndex = BitConverter.ToInt16(data, index); break; default: //忽略定长字段和其他不支持以及不愿意考虑的字段 break; } } //获取完毕 }
private void ExeSqlCommand(string sql) { using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection()) { conn.ConnectionString = "Data Source=DEV-PC\\SQLEXPRESS;Initial Catalog=dbLogTest;Integrated Security=True"; conn.Open(); using (System.Data.SqlClient.SqlCommand command = conn.CreateCommand()) { //察看dbo.log_test对象的sql日志 command.CommandText = sql; System.Data.SqlClient.SqlDataReader reader = command.ExecuteReader(); //根据表字段的顺序建立字段数组, Datacolumn[] columns = new Datacolumn[] { new Datacolumn("id", System.Data.SqlDbType.Int), new Datacolumn("code", System.Data.SqlDbType.Char,10), new Datacolumn("name", System.Data.SqlDbType.VarChar), new Datacolumn("date", System.Data.SqlDbType.DateTime), new Datacolumn("memo", System.Data.SqlDbType.VarChar) }; //循环读取日志 while (reader.Read()) { byte[] data = (byte[])reader["r0"]; //byte[] data2 = (byte[])reader["r1"]; try { //把二进制数据结构转换为明文 TranslateData(data, columns); //TranslateData(data2, columns); string log = string.Format("ip xxxxx 对表{1}进行了{0}操作:", reader["operation"], reader["allocunitname"]); listBox1.Items.Add(log); listBox1.Items.Add("改动数据如下"); //Console.WriteLine("数据对象{1}的{0}操作:", reader["operation"], reader["allocunitname"]); foreach (Datacolumn c in columns) { listBox1.Items.Add(string.Format("{0} = {1}", c.Name, c.Value)); //Console.WriteLine("{0} = {1}", c.Name, c.Value); } listBox1.Items.Add("[Stop]"); upLogs(log, 2); } catch (Exception ex) { MessageBox.Show(ex.Message); } } reader.Close(); } conn.Close(); } }