程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#基礎-FileStream實現多線程斷點續傳,

C#基礎-FileStream實現多線程斷點續傳,

編輯:C#入門知識

C#基礎-FileStream實現多線程斷點續傳,


一、前言

       網上有許多的多線程斷點續傳操作,但總是寫的很雲裡霧裡,或者寫的比較坑長。由於這幾個月要負責公司的在線升級項目,所以正好順便寫了一下

       代碼如下:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.IO;
  6 using System.Threading;
  7 using System.Threading.Tasks;
  8 
  9 namespace ConsoleStream
 10 {
 11     class Program
 12     {
 13         static void Main(string[] args)
 14         {
 15             string LocalSavePath = @"E:\Test\Test\local\1.msi";  //本地目標文件路徑
 16 
 17             System.IO.FileInfo SeverFilePath = new FileInfo(@"E:\Test\Test\server\1.msi"); //服務器待文件路徑
 18             long FileLength = SeverFilePath.Length; //待下載文件大小
 19 
 20             
 21             Console.WriteLine("Start Configuration");
 22             int PackCount = 0;  //初始化數據包個數
 23 
 24             long PackSize = 10240000; //數據包大小
 25 
 26             if (FileLength % PackSize> 0)
 27             {
 28                 PackCount = (int)(FileLength / PackSize) + 1;
 29             }
 30 
 31             else
 32             {
 33                 PackCount = (int)(FileLength / PackSize);
 34             }
 35 
 36 
 37             Console.WriteLine("Start Recieve");
 38             var tasks = new Task[PackCount];  //多線程任務
 39 
 40             for (int index = 0; index < PackCount; index++)
 41             {
 42                
 43 
 44                 int Threadindex = index; //這步很關鍵,在Task()裡的絕對不能直接使用index
 45                 var task = new Task(() =>
 46                 {
 47                     string tempfilepath = @"E:\Test\Test\temp\" + "QS_" + Threadindex.ToString() + "_" + PackCount.ToString(); //臨時文件路徑
 48 
 49                     using (System.IO.FileStream tempstream = new System.IO.FileStream(tempfilepath, FileMode.Create, FileAccess.Write, FileShare.Write))
 50                     {
 51                         int length = (int)Math.Min(PackSize, FileLength - Threadindex * PackSize);
 52 
 53                         var bytes = GetFile(Threadindex, length);
 54 
 55                         tempstream.Write(bytes, 0, length);
 56                         tempstream.Flush();
 57                         tempstream.Close();
 58                         tempstream.Dispose();
 59                     }
 60                 });
 61                 tasks[Threadindex] = task;
 62                 task.Start();
 63             }
 64 
 65             Task.WaitAll(tasks); //等待所有線程完成
 66             Console.WriteLine("Recieve End");
 67 
 68 
 69             //檢測有哪些數據包未下載
 70             Console.WriteLine("Start Compare");
 71             DirectoryInfo TempDir = new DirectoryInfo(@"E:\Test\Test\temp"); //臨時文件夾路徑
 72             List<string> Comparefiles = new List<string>();
 73             bool hasfile = false;
 74             for (int i = 0; i < PackCount; i++)
 75             {
 76                 foreach (FileInfo Tempfile in TempDir.GetFiles())
 77                 {
 78                     if (Tempfile.Name.Split('_')[1] == i.ToString())
 79                     {
 80                         hasfile = true;
 81                         break;
 82                     }
 83                 }
 84                 if (hasfile == false)
 85                 {
 86                     Comparefiles.Add(i.ToString());
 87                 }
 88             }
 89 
 90             //最後補上這些缺失的文件
 91             if (Comparefiles.Count > 0)
 92             {
 93                 foreach (string com_index in Comparefiles)
 94                 {
 95                     string tempfilepath = @"E:\Test\Test\temp\" + "QS_" + com_index.ToString() + "_" + PackCount.ToString();                    
 96                     using (System.IO.FileStream Compstream = new System.IO.FileStream(tempfilepath, FileMode.Create, FileAccess.Write, FileShare.Write))
 97                     {
 98                         int length = (int)Math.Min(PackSize, FileLength - Convert.ToInt32(com_index) * PackSize);
 99                         var bytes = GetFile(Convert.ToInt32(com_index), length);
100                         Compstream.Write(bytes, 0, length);
101                         Compstream.Flush();
102                         Compstream.Close();
103                         Compstream.Dispose();
104                     }
105                 }
106 
107             }
108             Console.WriteLine("Compare End");
109 
110 
111             //准備將臨時文件融合並寫到1.msi中
112             Console.WriteLine("Start Write");
113             using (System.IO.FileStream writestream = new System.IO.FileStream(LocalSavePath, FileMode.Create, FileAccess.Write, FileShare.Write))
114             {
115                 foreach (FileInfo Tempfile in TempDir.GetFiles())
116                 {
117                     using (System.IO.FileStream readTempStream = new System.IO.FileStream(Tempfile.FullName, System.IO.FileMode.Open, System.IO.FileAccess.Read, FileShare.ReadWrite))
118                     {
119                         long onefileLength = Tempfile.Length;
120                         byte[] buffer = new byte[Convert.ToInt32(onefileLength)];
121                         readTempStream.Read(buffer, 0, Convert.ToInt32(onefileLength));
122                         writestream.Write(buffer, 0, Convert.ToInt32(onefileLength));
123                     }
124                 }
125                 writestream.Flush();
126                 writestream.Close();
127                 writestream.Dispose();
128             }
129             Console.WriteLine("Write End");
130 
131 
132 
133             //刪除臨時文件
134             Console.WriteLine("Start Delete Temp Files");
135             foreach (FileInfo Tempfile in TempDir.GetFiles())
136             {
137                 Tempfile.Delete();
138             }
139             Console.WriteLine("Delete Success");
140             Console.ReadKey();         
141         }
142 
143 
144         //這個方法可以放到Remoting或者WCF服務中去,然後本地調用該方法即可實現多線程斷點續傳
145         public static byte[] GetFile(int start, int length)
146         {
147             string SeverFilePath = @"E:\Test\Test\server\1.msi";
148             using (System.IO.FileStream ServerStream = new System.IO.FileStream(SeverFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read, FileShare.ReadWrite,1024,true))
149             {
150                 byte[] buffer = new byte[length];
151                 ServerStream.Position = start;
152                 ServerStream.Read(buffer, 0, length);
153                 return buffer;
154             }
155         }
156 
157        
158     }
159 }

 

二、討論      

        需要注意的是第44行,不能直接使用index變量在Task()裡進行操作,而是要將它賦給Threadindex,讓Threadindex在Task()裡,不然會直接報錯,為什麼呢?

        答案在此:http://bbs.csdn.net/topics/390769774

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved