关于C++结构体与C#结构体对应,以及解析BLOB块

1 篇文章 0 订阅

关于C++结构体与C#结构体对应,以及解析BLOB块

第一部分

需求

  1. c++结构体数据以二进制形式写入Oracle blob 中,
  2. c# 读取对应blob,解析成对应结构体。
  3. 存储的blob内容为一张表,记录了不同location 处,多个属性的值
    | location | filed_1 | filed_2 | … | field_7 |
    | value | filed_value | filed_value | … | field_value |
    | location | filed_1 | filed_2 | … | field_7 |
// .cpp
#pragma pack(1)
struct BlobData
{
	short h[10];
	char ColumName[动态行数][40];
	double CurveData[动态行数][动态列数];
};
#pragma pack()
 [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct RECORDS_DATA
    {
        public int Cols;
        public int Rows;
        public int FieldsOffset;
        public int DataOffset;
        public int BufferSizetelte;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512 * 1024)]
        public byte[] Data;
    }

问题

  1. c++ 和 c# 数据类型的对应;
  2. c# 如何将 blob 解析为 结构体?

类型对应

	看上述代码:
	c++ 		c#
	int			int
	long		int
	double	    double

解析

   static void Main(string[] args)
        {
            string constring = string.Concat(
               @"Data Source=",
               @"    (DESCRIPTION=",
               @"        (ADDRESS_LIST=",
               @"            (ADDRESS=",
               @"                (PROTOCOL=TCP)",
               @"                (HOST=127.0.0.1)",
               @"                (PORT=1521)",
               @"            )",
               @"        )",
               @"        (CONNECT_DATA=",
               @"            (SERVICE_NAME=服务名)",
               @"        )",
               @"    );",
               @"Persist Security Info=True;",
               @"User Id=账户;",
               @"Password=密码"
               );

            OracleConnection conn = new OracleConnection(constring);

            try
            {
                conn.Open();
                OracleCommand com = conn.CreateCommand();
                com.CommandText = "SELECT blob_data from table WHERE xxx";
                OracleDataReader odr = com.ExecuteReader();
                while (odr.Read())

                {

                    #region 获取blob数据
                    // 将blob存入byte数组中
                    byte[] binary_data = (byte[])odr.GetOracleLob(0).Value;

					//恶心的托管内存
                    int len = Marshal.SizeOf(typeof(RECORDS_DATA));
                    int act_len = binary_data.Length;

                    unsafe
                    {
                        Console.WriteLine("len: " + len);
                        Console.WriteLine("binary_data: " + act_len);

                        IntPtr p = Marshal.AllocHGlobal(len);
                        Marshal.Copy(binary_data, 0, p, act_len);

                        // 将内存空间转换为目标结构体
                        var dbh = (RECORDS_DATA)Marshal.PtrToStructure(p, typeof(RECORDS_DATA));

                        var colNum = dbh.Cols;
                        var rowNum = dbh.Rows;

                        Console.WriteLine("Cols: " + dbh.Cols); //7
                        Console.WriteLine("Rows: " + dbh.Rows); //546
                        Console.WriteLine("DataOffset: " + dbh.DataOffset);//300
                        Console.WriteLine("FieldsOffset: " + dbh.FieldsOffset);//20
                        Console.WriteLine("BufferSizetelte: " + dbh.BufferSizetelte);//20
                        #endregion


                        #region 解析表头
                        // 手动解析,没有存放到结构体
                        var da = dbh.Data;
                        var field_begin = (char*)(IntPtr.Add(p, dbh.FieldsOffset));
                        Console.WriteLine("print filed******************************************");//20
                        for (int col = 0; col < dbh.Cols; col++)
                        {
                            string filed_name = Marshal.PtrToStringAnsi(IntPtr.Add(p, dbh.FieldsOffset + 40 * col));
                            Console.WriteLine("filed_name: " + filed_name);
                            short filed_type = Marshal.ReadInt16(IntPtr.Add(p, dbh.FieldsOffset + 40 * col), 32);
                            Console.WriteLine("filed_type: " + filed_type);
                            short filed_size = Marshal.ReadInt16(IntPtr.Add(p, dbh.FieldsOffset + 40 * col), 32 + 2);
                            Console.WriteLine("filed_size: " + filed_size);
                            int filed_offset = Marshal.ReadInt32(IntPtr.Add(p, dbh.FieldsOffset + 40 * col), 32 + 2 + 2);
                            Console.WriteLine("filed_offset: " + filed_offset);
                        }
                        Console.WriteLine("*****************************************************");
                        #endregion

                        #region 解析数据体
                        //手动解析,没有映射到structure中

                        //数据起始地址
                        var data_begin = (IntPtr.Add(p, dbh.DataOffset));

                        int startIndex = 0;
                        int length = dbh.Rows * dbh.Cols;
                        // 最终的二维表数据
                        double[,] dst = new double[dbh.Rows, dbh.Cols];
                        double[] src = new double[dbh.Rows * dbh.Cols];
                        Marshal.Copy(data_begin, src, startIndex, length);

                                                dst format 
                        ///
                         dst       location  thinkness   width   finishtemp  CROWN  FLATNESS  WEDGE
                         dst[0]       0.947    0.0515       
                         dst[1]
                        
                        for (int i = 0; i < rowNum; ++i)
                        {
                            for (int j = 0; j < colNum; ++j)
                            {
                                dst[i, j] = src[i * colNum + j];
                            }
                        }


                        for (int row = 0; row < rowNum; ++row)
                        {
                            Console.WriteLine("location: " + dst[row, 0] + " ,thinkness: " + dst[row, 1]);
                        }
                        #endregion

                        Marshal.FreeHGlobal(p);
                    }

                }
                odr.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("error: " + ex.Message);
            }
            finally
            {
                conn.Close();
            }

总结

  1. 刚接触c#的托管内存,感觉用起来不舒服,后来理清思路,还算可以,但感觉还是c++好用。
  2. 存在一个问题,如何直接将数据内存映射到结构体中, 暂时思路就是将二维数据读入一维数组中,然后手动转为二维数据。

有兴趣请关注公众号:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值