C#读取二进制文件入数据库

2009-05-26 17:37


本来我对文件操作不是很了解,以前只做了数据导出到excel表格的文件操作,是数据导出的,虽说数据导出和数据导入只是个相反的过程,也没什么难的,但是在实际操作中还是遇到了不大不小的问题,这只能说我菜了,呵呵
的确本人确实很菜,但还是想把下边的读取二进制文件入数据库域大家一起分享,并请高手继续指教
读取二进制文件入数据库我分为三个步骤:
1,读取二进制文件入结构体,当然定义结构体之前必须知道二进制文件存储的方式是什么,否则将读出乱码来
在c#中定义有固定大小的结构体域其他语言不同的是得费点事拉
在结构体内部变量中声明指定大小的变量这样来声明
以下是本人声明的结构体例子

using  System.Runtime.InteropServices;
/// <summary>
     /// 消费账单结构体
     /// </summary>
     public struct UseBill_InfoTemp
     {
         [MarshalAs(UnmanagedType.U1, SizeConst = 8)]
         public byte[] usebill_id;//账单id
         [MarshalAs(UnmanagedType.U1, SizeConst = 8)]
         public byte[] manager_id;//运营商id
         [MarshalAs(UnmanagedType.U1, SizeConst = 64)]
         public byte[] manager_name;//运营商名称
         [MarshalAs(UnmanagedType.U1, SizeConst = 8)]
         public byte[] agent_id;//代理商id
         [MarshalAs(UnmanagedType.U1, SizeConst = 64)]
         public byte[] agent_name;//代理商名称
         [MarshalAs(UnmanagedType.U1, SizeConst = 8)]
         public byte[] hotel_group_id;
         [MarshalAs(UnmanagedType.U1, SizeConst = 8)]
         public byte[] hotel_id;//宾馆id
         [MarshalAs(UnmanagedType.U1, SizeConst = 64)]
         public byte[] hotel_name;//宾馆名称
         [MarshalAs(UnmanagedType.U1, SizeConst = 8)]
         public byte[] provider_id;//广告商id
         [MarshalAs(UnmanagedType.U1, SizeConst = 64)]
         public byte[] provider_name;//广告商名称
         [MarshalAs(UnmanagedType.U1, SizeConst = 8)]
         public byte[] guset_id;//顾客id
         [MarshalAs(UnmanagedType.U1, SizeConst = 20)]
         public byte[] guest_name;//顾客名称
         [MarshalAs(UnmanagedType.I2)]
         public ushort flag;//标识
         [MarshalAs(UnmanagedType.I2)]
         public ushort main_type;//主类型
         [MarshalAs(UnmanagedType.U1, SizeConst = 20)]
         public byte[] main_type_name;//主类型名称
         [MarshalAs(UnmanagedType.I2)]
         public ushort sub_type;//子类型
         [MarshalAs(UnmanagedType.U1, SizeConst = 20)]
         public byte[] sub_type_name;//子类型名称
         [MarshalAs(UnmanagedType.U1,SizeConst=14)]
         public byte[] use_time;//消费使用时间
         [MarshalAs(UnmanagedType.U1, SizeConst = 4)]
         public byte[] room_id;//房间id
         [MarshalAs(UnmanagedType.U1,SizeConst=10)]
         public byte[] room_no;//房间编号
         [MarshalAs(UnmanagedType.I2)]
         public ushort fee;//消费金额
         [MarshalAs(UnmanagedType.U1, SizeConst = 8)]
         public byte[] info_id;
         [MarshalAs(UnmanagedType.U1, SizeConst = 64)]
         public byte[] chs_name;//名称
     }


上面就是我定义的结构体,当然在读取数据的时候也是知道数据是按照扫描顺序存贮在二进制文件中的,下边是我读取二进制文件入结构体中的代码

FileStream fs = new FileStream(dtFileinfo.Rows[i]["filePath"].ToString(), FileMode.Open);
                         BinaryReader br = new BinaryReader(fs, Encoding.GetEncoding("gb2312"));
                         string File_Head = Encoding.Default.GetString(br.ReadBytes(10));
                         if (File_Head.Length > 0)
                         {
                             for (int j = 0; j < (fs.Length - 10) / 74; j++)//74是结构体的总字节数大小
                             {
                                 use_billTemp.usebill_id = br.ReadBytes(8);
                                 use_billTemp.manager_id = br.ReadBytes(8);
                                 use_billTemp.manager_name = br.ReadBytes(64);
                                 use_billTemp.agent_id = br.ReadBytes(8);
                                 use_billTemp.manager_name = br.ReadBytes(64);
                                 use_billTemp.hotel_id = br.ReadBytes(8);
                                 use_billTemp.hotel_name = br.ReadBytes(64);
                                 use_billTemp.provider_id = br.ReadBytes(8);
                                 use_billTemp.provider_name = br.ReadBytes(64);
                                 use_billTemp.guset_id = br.ReadBytes(8);
                                 use_billTemp.guset_name = br.ReadBytes(20);
                                 use_billTemp.flag = br.ReadUInt16();
                                 use_billTemp.main_type = br.ReadUInt16();
                                 use_billTemp.sub_type = br.ReadUInt16();
                                 use_billTemp.use_time = br.ReadBytes(14);
                                 use_billTemp.room_id = br.ReadBytes(4);
                                 use_billTemp.fee = br.ReadUInt16();
                                 use_billTemp.info_id = br.ReadBytes(8);
                                 use_billTemp.chs_name = br.ReadBytes(64);
                                 use_billTemp.hotel_group_id = br.ReadBytes(8);
                          }


二进制文件就是按照上面的顺序存储的,所以我知道每个字段该读多少,一行共读多少字段,然后才循环下一行继续重复读入数据
一行一行的存入数据库

using  System;
 using  System.Collections.Generic;
 using  System.ComponentModel;
 using  System.Data;
 using  System.Drawing;
 using  System.Text;
 using  System.Windows.Forms;
 using  System.Runtime.InteropServices;
 using  System.IO;

 namespace  StructTest
 {
      public   partial   class  Form1 : Form
     {

          string  filename  =   @" d:/poi.st " ;

          #region  结构体 

          // 90 
 
         [StructLayout(LayoutKind.Sequential), Serializable]
          public   struct  MY_STRUCT
         {
              public   double  x;           // 点的经度坐标 
              public   double  y;           // 点的纬度坐标 
             [MarshalAs(UnmanagedType.ByValTStr, SizeConst  =   40 )]
              public   string  Name;         // Name[40];  // 名称 
              public   long  PointID;   // 点的ID号 
              public   long  TypeCode;  // 客户不使用该字段 
         }

          #endregion 

          public  Form1()
         {
             InitializeComponent();
         }

          private   void  button1_Click( object  sender, EventArgs e)
         {
             MY_STRUCT[] arr  =   new  MY_STRUCT[ 2 ];

             MY_STRUCT np  =   new  MY_STRUCT();
             np.x  =   114.123456 ;
             np.y  =   23.56789 ;
             np.Name  =   " 珠海市政府 " ;
             np.PointID  =  Convert.ToInt64( 1234 );
             np.TypeCode  =  Convert.ToInt64( 65 );

             arr[ 0 ]  =  np;

             np  =   new  MY_STRUCT();
             np.x  =   115.123456 ;
             np.y  =   24.56789 ;
             np.Name  =   " 珠海市政府2 " ;
             np.PointID  =  Convert.ToInt64( 1235 );
             np.TypeCode  =  Convert.ToInt64( 66 );

             arr[ 1 ]  =  np;

              int  structSize  =  Marshal.SizeOf( typeof (MY_STRUCT));
              byte [] temp  =   new   byte [structSize  *  arr.Length];
              byte [] temp1  =  Struct2Byte(arr[ 0 ]);
              byte [] temp2  =  Struct2Byte(arr[ 1 ]);

             Array.Copy(temp1,  0 , temp,  0 , temp1.Length);
             Array.Copy(temp2,  0 , temp, structSize, temp2.Length);

             WriteInfo(temp);
         }


          public   void  WriteInfo( byte [] bt)
         {
              if  (File.Exists(filename))
             {
                 File.Delete(filename);
                  return ;
             }

             FileStream fs  =   new  FileStream(filename, FileMode.Create);
             BinaryWriter bw  =   new  BinaryWriter(fs);
             bw.Write(bt);
             bw.Flush();

             bw.Close();
             fs.Close();

             MessageBox.Show( " 保存成功! " );
         }

          public   byte [] ReadInfo( string  file)
         {
             FileStream fs  =   new  FileStream(file, FileMode.Open);
             BinaryReader br  =   new  BinaryReader(fs);

              byte [] bt  =  br.ReadBytes( 144 );
             br.Close();
             fs.Close();

              return  bt;
         }

          private   void  button2_Click( object  sender, EventArgs e)
         {
              byte [] bt  =  ReadInfo(filename);

              int  structSize  =  Marshal.SizeOf( typeof (MY_STRUCT));
              int  num  =  bt.Length  /  structSize;

              for  ( int  i  =   0 ; i  <  num; i ++ )
             {
                  byte [] temp  =   new   byte [structSize];
                 Array.Copy(bt, i  *  structSize, temp,  0 , structSize);

                 MY_STRUCT np  =   new  MY_STRUCT();
                 np  =  Byte2Struct(temp);
             }
         }


          private  MY_STRUCT Byte2Struct( byte [] arr)
         {
              int  structSize  =  Marshal.SizeOf( typeof (MY_STRUCT));
             IntPtr ptemp  =  Marshal.AllocHGlobal(structSize);
             Marshal.Copy(arr,  0 , ptemp, structSize);
             MY_STRUCT rs  =  (MY_STRUCT)Marshal.PtrToStructure(ptemp,  typeof (MY_STRUCT));
             Marshal.FreeHGlobal(ptemp);
              return  rs;
         }

          private   byte [] Struct2Byte(MY_STRUCT s)
         {
              int  structSize  =  Marshal.SizeOf( typeof (MY_STRUCT));
              byte [] buffer  =   new   byte [structSize];
              // 分配结构体大小的内存空间  
             IntPtr structPtr  =  Marshal.AllocHGlobal(structSize);
              // 将结构体拷到分配好的内存空间  
             Marshal.StructureToPtr(s, structPtr,  false );
              // 从内存空间拷到byte数组  
             Marshal.Copy(structPtr, buffer,  0 , structSize);
              // 释放内存空间  
             Marshal.FreeHGlobal(structPtr);
              return  buffer;
         }

     }
 }

 

C#结构体和字节数组的转换


   在写C#TCP通信程序时,发送数据时,只能发送byte数组,处理起来比较麻烦不说,如果是和VC6.0等写的程序通信的话,很多的都是传送结构体,在 VC6.0中可以很方便的把一个char[]数组转换为一个结构体,而在C#却不能直接把byte数组转换为结构体,要在C#中发送结构体,可以按以下方 法实现:
(1)定义结构体:
 

//命名空间
     using System.Runtime.InteropServices;    //注意这个属性不能少
     [StructLayoutAttribute(LayoutKind.Sequential,CharSet=CharSet.Ansi,Pack=1)]
     struct TestStruct
     {
         public int c;
         //字符串,SizeConst为字符串的最大长度
         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
         public string str;
         //int数组,SizeConst表示数组的个数,在转换成
         //byte数组前必须先初始化数组,再使用,初始化
         //的数组长度必须和SizeConst一致,例test = new int[6];
         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
         public int[] test;
     }

(2)结构体转byte数组:
       

<summary>
         /// 结构体转byte数组
         /// </summary>
         /// <param name="structObj">要转换的结构体</param>
         /// <returns>转换后的byte数组</returns>
         public static byte[] StructToBytes(object structObj)
        {
             //得到结构体的大小
             int size = Marshal.SizeOf(structObj);
             //创建byte数组
             byte[] bytes = new byte[size];
             //分配结构体大小的内存空间
             IntPtr structPtr = Marshal.AllocHGlobal(size);
             //将结构体拷到分配好的内存空间
             Marshal.StructureToPtr(structObj, structPtr, false);
             //从内存空间拷到byte数组
             Marshal.Copy(structPtr, bytes, 0, size);
             //释放内存空间
             Marshal.FreeHGlobal(structPtr);
             //返回byte数组
             return bytes;
         }


(3)byte数组转结构体:
     

/// <summary>
         /// byte数组转结构体
         /// </summary>
         /// <param name="bytes">byte数组</param>
         /// <param name="type">结构体类型</param>
         /// <returns>转换后的结构体</returns>
         public static object BytesToStuct(byte[] bytes,Type type)
         {
             //得到结构体的大小
             int size = Marshal.SizeOf(type);
             //byte数组长度小于结构体的大小
             if (size > bytes.Length)
             {
                 //返回空
                 return null;
             }
             //分配结构体大小的内存空间
             IntPtr structPtr = Marshal.AllocHGlobal(size);
             //将byte数组拷到分配好的内存空间
             Marshal.Copy(bytes,0,structPtr,size);
             //将内存空间转换为目标结构体
             object obj = Marshal.PtrToStructure(structPtr, type);
             //释放内存空间
             Marshal.FreeHGlobal(structPtr);
             //返回结构体
             return obj;
         }