多线程从数据库二进制字段转成文件

旧系统的文件是以二进制保存在数据库字段中。

做系统切换时要把这些文件转换成文件

用到委托的多线程,这个以前也写过,这次写的时候又查了好久,

放在这标记一下。

View Code
  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 using System.IO;
 10 using System.Threading;
 11 
 12 namespace LZDataExport
 13 {
 14     public partial class CreateFile : Form
 15     {
 16         private DataTable dtLZ_KJ_CollectFile = null;
 17         DbHelperSQL LZdbHelper = null;
 18         string CurrentPath = "";
 19         MyDeleGateBytesToFile[] myDeleGates = null;
 20         IAsyncResult[] results = null;
 21         DateTime dtS = DateTime.Now;
 22         int ThreadNum = 10;
 23         int CompleteNum = 10;
 24         private Object thisLock = new Object();
 25         private DataTable dtAllFsFileId = null;
 26         public CreateFile()
 27         {
 28             InitializeComponent();
 29             //不设置的话线程回调时会提示:  线程间操作无效: 从不是创建控件的线程访问它。
 30             Control.CheckForIllegalCrossThreadCalls = false;
 31         }
 32 
 33         private void Start_Click(object sender, EventArgs e)
 34         {
 35             Start.Text = "处理中。。";
 36             Start.Enabled = false;
 37             dtAllFsFileId = new DbHelperSQL("JHDB_KJ").Query("select * from CollectFile_KJ").Tables[0];
 38             //理正数据库
 39             LZdbHelper = new DbHelperSQL("LZDB");
 40             //当前路径
 41             CurrentPath = Application.StartupPath + @"\KJ\Collect\";
 42             if (!Directory.Exists(CurrentPath))
 43             {
 44                 Directory.CreateDirectory(CurrentPath);
 45             }
 46             //获取所有附件记录表
 47             dtLZ_KJ_CollectFile = LZdbHelper.Query("select top 100 Id,FK_Value,FIleName,FileExt,FileSize from FC_InfoAttach").Tables[0];
 48             dtS = DateTime.Now;
 49             TimeLog.AppendText("开始:" + dtS.ToString("yyyy-MM-dd HH:mm:ss:ff") + "\r");
 50             myDeleGates = new MyDeleGateBytesToFile[ThreadNum];
 51             results = new IAsyncResult[ThreadNum];            
 52             TimeLog.AppendText("总条数:" + dtLZ_KJ_CollectFile.Rows.Count.ToString() + "\r");
 53             int length = dtLZ_KJ_CollectFile.Rows.Count / ThreadNum;
 54             for (int i = 0; i < ThreadNum; i++)
 55             {
 56                 myDeleGates[i] = new MyDeleGateBytesToFile(BytesToFile);
 57                 int startNum = i * length;
 58                 int endNum = 0;
 59                 if (i == ThreadNum - 1)
 60                 {
 61                     endNum = dtLZ_KJ_CollectFile.Rows.Count;
 62                 }
 63                 else
 64                 {
 65                     endNum = (i + 1) * length;
 66                 }
 67                 AsyncCallback acb = new AsyncCallback(CallBackMethod);
 68                 //i会加到results[i].AsyncState 在回调时用到
 69                 results[i] = myDeleGates[i].BeginInvoke(startNum, endNum, acb, i);
 70                 TimeLog.AppendText("线程[" + i.ToString() + "]记录起止数:" + startNum.ToString() + "-" + endNum.ToString() + "\r");
 71             }
 72         }
 73 
 74         /// <summary>
 75         /// 异步回调方法
 76         /// </summary>
 77         /// <param name="ar">开始异步时参数</param>
 78         private void CallBackMethod(IAsyncResult ar)
 79         {
 80             //不加锁的话 同时返回就会出错。
 81             lock (thisLock)
 82             {
 83                 int i = (int)ar.AsyncState;
 84                 DateTime dtE = DateTime.Now;                
 85                 TimeLog.AppendText("线程[" + i.ToString() + "]结束于:" + dtE.ToString("yyyy-MM-dd HH:mm:ss:ff") + "\r");
 86                 TimeSpan tsS = new TimeSpan(dtS.Ticks);
 87                 TimeSpan tsE = new TimeSpan(dtE.Ticks);
 88                 TimeSpan teR = tsE.Subtract(tsS);
 89                 TimeLog.AppendText("用了:" + teR.TotalMilliseconds + "\r");
 90                 LogTxt.AppendText(myDeleGates[i].EndInvoke(results[i]).ToString());//myDeleGates[i].EndInvoke(ar).ToString() 也可以
 91                 CompleteNum = CompleteNum - 1;
 92                 if (CompleteNum == 0)
 93                 {                    
 94                     MessageBox.Show("导入完成");
 95                 }
 96             }
 97         }
 98 
 99 
100         /// <summary>
101         /// 二进制转成文件 跟定义的委托相同的签名
102         /// </summary>
103         /// <param name="StartNum">开始数</param>
104         /// <param name="EndNum">结束数</param>
105         /// <returns>StringBuilder</returns>
106         private StringBuilder BytesToFile(int StartNum, int EndNum)
107         {
108             StringBuilder sb = new StringBuilder();
109             for (int i = StartNum; i < EndNum; i++)
110             {
111                 DataRow dr = dtLZ_KJ_CollectFile.Rows[i];
112                 string FileName = CommandFunction.ObjectToStr(dtAllFsFileId.Select("LZFC_InfoAttach_Id='" + CommandFunction.ObjectToStr(dr["Id"]) + "'")[0]["FsFileId"]) + "_" + CommandFunction.ObjectToStr(dr["FIleName"]) + "." + CommandFunction.ObjectToStr(dr["FileExt"]);
113                 //CommandFunction.ObjectToStr(dr["Id"]) + "_" + CommandFunction.ObjectToStr(dr["FIleName"]) + "." + CommandFunction.ObjectToStr(dr["FileExt"]);
114                 string FullFilePath = "";
115                 FullFilePath = CurrentPath + FileName; 
116                 if (File.Exists(FullFilePath))
117                 {                    
118                     sb.Append("[" + FileName + "]已经创建过\r");                    
119                 }
120                 else
121                 {
122                     object FileData = LZdbHelper.GetSingle("select FileData from FC_InfoAttach where Id='" + dr["Id"].ToString() + "'");
123                     Byte[] Files = (Byte[])FileData;
124                     BinaryWriter bw = new BinaryWriter(File.Open(FullFilePath, FileMode.OpenOrCreate));
125                     bw.Write(Files);
126                     bw.Close();
127                     sb.Append("创建文件[" + FileName + "]成功\r");
128                 }                
129             }
130             return sb;
131 
132         }
133 
134         //定义一个委托
135         private delegate StringBuilder MyDeleGateBytesToFile(int StartNum, int EndNum);
136 
137 
138     }
139 }

其中

1  object FileData = LZdbHelper.GetSingle("select FileData from FC_InfoAttach where Id='" + dr["Id"].ToString() + "'");

去数据库取二进制数据时,如果该文件很大,程序会提示 数据库操作超时。

因此在GetSingle方法里面设置了一下超时时间

View Code
 1 /// <summary>
 2         /// 执行一条计算查询结果语句,返回查询结果(object)。
 3         /// </summary>
 4         /// <param name="SQLString">计算查询结果语句</param>
 5         /// <returns>查询结果(object)</returns>
 6         public object GetSingle(string SQLString)
 7         {
 8             using (SqlConnection connection = new SqlConnection(connectionString))
 9             {
10                 using (SqlCommand cmd = new SqlCommand(SQLString, connection))
11                 {
12                     try
13                     {
14                         connection.Open();
15                         //设置取数据时的超时时间
16                         cmd.CommandTimeout = 0;
17                         object obj = cmd.ExecuteScalar();
18                         if ((Object.Equals(obj, null)) || (Object.Equals(obj, System.DBNull.Value)))
19                         {
20                             return null;
21                         }
22                         else
23                         {
24                             return obj;
25                         }
26                     }
27                     catch (System.Data.SqlClient.SqlException e)
28                     {
29                         connection.Close();
30                         throw e;
31                     }
32                 }
33             }
34         }

posted on 2012-07-20 12:01  thegavincheng  阅读(257)  评论(0编辑  收藏  举报