Asp.Net教程,WinForm教程,Asp.Net MVC,vs2008教程,vs2010教程,Silverlight技术,源码下载,Asp.Net视频教程
全站热门标签
vs2010 Silverlight 存储过程 水晶报表 ADO.NET JavaScript LINQ AjaxPro DataGridView 面向对象 Extjs GridView XML DevExpress HTML教程 Oracle jQuery 分页 GDI+ Visual C++2010 MySQL Office2010 WPF MVC Dojo WCF4.0 VB.NET Sql2005 textbox cookie WCF WinForm Discuz!NT SQL经典语句 T-SQL checkbox ASPxGridView F# asp.net SQL VS2008新特性 DropDownList Access TreeView Ajax VS2008 页面执行时间 Flex 字符串 回调 VB2005 DataSet C#时间 ASP.NET性能优化 用户在线检测 动画
FrameworkC#技术 VB.NET VC.NET WCF WPF
当前位置: 主页 > WinForm教程 > C#技术 >

断点续传、多线程上载

时间:2010-08-31 23:42来源:未知 作者:admin 点击:

缘起:客户每天都有大量文件上传服务器。这些文件很多,并且体积挺大,FTP有时候会出一些问题,导致传递失败,要重新上传。

基本解决方案:

1:把文件分割成块,每次只是传递一个文件块。

2:一个文件可以起多个发送任务(线程),同时发送。

3:记录文件发送状态,在网络出现问题时(或者客户端意外终止),知道上次发送文件大小和位置指针。再重新链接以后,继续发送。

对象和线程

这里面涉及到一个显示窗体form1,有timer可以随时更新发送状态;一个上传类Uploader(对应于一个文件);Task对象(也就是一个文件);FileThunk对象(每一个任务,对应于一个线程);WebService接受文件类。

发送状态需要记录在数据库。测试状态下,数据记录在xml文件。基本格式如下:

     

Code
<tasks>
  <task name="contact.txt" percentage="" totalSeconds="" localFile="" remoteFile="" fileSize="">
   <thread name="thread1" begin="" end="" lastTime=""></thread>

  </task>
</tasks>


数据表结构也基本类似这样。

核心代码:

1:form1. 这个主要是显示。主要函数是 添加任务(Task);更新任务状态
 
浏览文件,创建任务
 1   private void btn_browse_Click(object sender, EventArgs e)
 2         {
 3             //browse to select files
 4             OpenFileDialog ofd = new OpenFileDialog();
 5             ofd.Multiselect = true;
 6             DialogResult dr= ofd.ShowDialog();
 7
 8             _taskList = new ArrayList();
 9             for (int i = 0; i < ofd.FileNames.Length; i++)
10             {
11                 Task t = new Task();
12                 t.FileChunkCount = Convert.ToInt32(this.txt_threadsPerFile.Text);
13                 t.LocalFile = ofd.FileNames[i];
14                 t.RemoteFile = Path.GetFileName(t.LocalFile);
15                 t.Name = Path.GetFileName(t.LocalFile);
16                 //t.Percentage=0;
17                 t.TotalSeconds=0;
18
19                 t.Init(); //init, split the file to upload
20
21                 _taskList.Add(t);
22                
23             }
24             //show in UI
25             this.dataGridView1.DataSource = GetUpdatedStatusAsDT(_taskList,0);
26         }
显示和更新状态,返回DataTable
 1   private DataTable GetUpdatedStatusAsDT(ArrayList list, int seconds)
 2         {
 3             DataTable dt = new DataTable();
 4             dt.Columns.Add("Name");
 5             dt.Columns.Add("FileSize");
 6             dt.Columns.Add("Percentage");
 7             dt.Columns.Add("TotalSeconds");
 8             dt.Columns.Add("LocalFile");
 9             dt.Columns.Add("RemoteFile");
10
11             for (int i = 0; i < list.Count; i++)
12             {
13                 //update task status to db
14                 Task t = (list[i] as Task);
15                 t.TotalSeconds += seconds;//running time
16                 t.Save();//save the status to db, so next time can load the status to continue.
17
18                 DataRow dr = dt.NewRow();
19                 dr["Name"] = t.Name;
20                 dr["FileSize"] = t.FileSize;
21                 dr["Percentage"] = t.Percentage;
22                 dr["TotalSeconds"] = t.TotalSeconds;
23                 dr["LocalFile"] = t.LocalFile;
24                 dr["RemoteFile"] = t.RemoteFile;
25
26                 dt.Rows.Add(dr);
27             }
28             return dt;
29         }
执行任务
 1    private void btn_run_Click(object sender, EventArgs e)
 2         {
 3             //timmer to show the status
 4             Timer timer = new Timer();
 5             timer.Tick += new EventHandler(timer_Tick);
 6             timer.Interval = 2 * 1000; //every 2 seconds
 7             timer.Enabled = true;
 8             timer.Start();
 9             //
10             //continue
11             //find task from datasource (DB or xml) and continue
12             //ArrayList tasks = Task.LoadTasks();
13             //
14             ArrayList tasks = _taskList;  // get the task list.
15             //
16             for (int i = 0; i < tasks.Count; i++)
17             {
18                 Uploader uld = new Uploader(tasks[i] as Task);
19                 uld.Strat();
20             }
21         }
22

2:Uploader的核心代码:主要是启动线程。


Code
 1   public void Strat()
 2         {
 3             //_dataReceiver.Open(this._task.RemoteFile);//init webservice
 4
 5             #region test
 6             //if (!File.Exists(_task.RemoteFile))
 7             //{
 8             //    FileInfo fi = new FileInfo(_task.LocalFile);
 9
10             //    FileStream fst = new FileStream(_task.RemoteFile, FileMode.CreateNew);
11
12             //    BinaryWriter w = new BinaryWriter(fst);
13             //    byte[] ab = new byte[fi.Length];
14             //    w.Write(ab);
15             //    w.Close();
16             //    fst.Close();
17             //}
18             //
19             #endregion
20           
21             //main code. find each fileChunk, running in seperate thread
22             for (int i = 0; i < _task.FileChunks.Count; i++)
23             {
24                 FileChunk fc = (_task.FileChunks[i] as FileChunk);
25                 Thread thread = new Thread(new ThreadStart(fc.Upload));
26                 fc.RunningThread = thread;//asign thread to the fileChucks, to stop the task
27                 thread.Name = _task.Name + "_" + i.ToString();
28                 thread.Start();
29             }
30         }

3:Task类的主要代码:主要是初始化任务,其他诸如和对数据的保存/提取


Code
 1    public void Init()
 2         {
 3             //create new
 4            this.FileChunks = new ArrayList();
 5
 6             FileInfo fi = new FileInfo(LocalFile);
 7             FileSize = fi.Length;
 8
 9             long block = FileSize / this.FileChunkCount;
10             long index = 0;
11             for (int i = 0; i < this.FileChunkCount; i++)
12             {
13                 FileChunk fc = new FileChunk(this);
14                 fc.Begin = index;
15                 if (i==this.FileChunkCount-1)
16                     block = FileSize - index;
17                 index += block;
18                 fc.End = index;
19                 fc.LastTime = DateTime.Now;
20
21                 this.FileChunks.Add(fc);
22             }
23             //
24 
25         }

4:FileChunk的核心代码:主要是如何上传文件


Code
 1   /// <summary>
 2         /// main function
 3         /// </summary>
 4         public void Upload()
 5         {
 6             Stream fs = File.OpenRead(_task.LocalFile);
 7
 8             long len = 2 * 64 * 1024;// 2 * 64 * 1024;
 9 
10             while (Begin < End)
11             {
12                 if (End - Begin < len)
13                     len = End - Begin;
14                 byte[] data = new byte[len];
15                 fs.Position = Begin;
16                 fs.Read(data, 0, (int)len);
17             
18                 #region local test
19                 //Stream fs2 = File.OpenWrite(_task.RemoteFile);
20                 //fs2.Position = Begin;
21                 //fs2.Write(data, 0, (int)len);
22                 //fs2.Flush();
23                 //fs2.Close();
24                 //
25                 #endregion
26               
27                 //call webservice to receive the data. this can be a socket also.
28                 string res = this._task.DataReceiver.Receive(_task.RemoteFile, Begin, len, data);
29                 if (res == "ok")
30                 {
31                     //
32                     Begin += len;
33                     _task.Save();
34                 }
35                 else
36                 {
37                     //wait for next while,
38                 }
39
40             }
41         }

 


5:WebService的核心代码


Code
 [WebMethod]
    public string Receive(string file, long begin, long len, byte[] data)
    {
        _fileName = AppDomain.CurrentDomain.BaseDirectory + "\\tmp\\" + file;
        try
        {
            _fs = File.OpenWrite(_fileName);
            _fs.Position = begin;
            _fs.Write(data, 0, (int)len);
            _fs.Flush();
            _fs.Close();
            _fs = null;
            return "ok";
        }
        catch (Exception ex)
        {
            string s = ex.Message;
            return "retry";
        }

    }


   小结:

技术难度不大;现实实用;上传速度尚可。
 


 

 

(责任编辑:admin)
Tags:多线程 断点续传
责任编辑:admin
返回顶部
------分隔线----------------------------
推荐内容
骆驼户外男 真皮磨砂日常休闲鞋 低帮 2011秋冬新款 专柜正品特价 骆驼户外男 真皮磨砂日常休闲鞋 低帮 2011秋冬新款 专柜正品特价