一、前言
网上有许多的多线程断点续传操作,但总是写的很云里雾里,或者写的比较坑长。由于这几个月要负责公司的在线升级项目,所以正好用到
代码如下:
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
时间: 2024-10-24 21:49:30