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

时间: 2024-10-24 21:49:30

C#基础-FileStream实现多线程断点续传的相关文章

Android实现网络多线程断点续传下载

本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多线程断点需要什么功能? 1.多线程下载, 2.支持断点. 使用多线程的好处:使用多线程下载会提升文件下载的速度.那么多线程下载文件的过程是: (1)首先获得下载文件的长度,然后设置本地文件的长度. HttpURLConnection.getContentLength();//获取下载文件的长度 Ra

Java基础】并发 - 多线程

Java基础]并发 - 多线程 分类: Java2014-05-03 23:56 275人阅读 评论(0) 收藏 举报 Java 目录(?)[+] 介绍 Java多线程 多线程任务执行 大多数并发应用程序时围绕执行任务(task)进行管理的:所谓任务就是抽象的,离散的工作单元. 围绕执行任务来管理应用程序时,第一步是要指明一个清晰的任务边界.大多数应用服务器程序都选择了下面这个自然的任务辩解:单独的客户请求: 任务时逻辑上的单元: 任务 Runnable 表示一个任务单元(java.lang)

Android 多线程断点续传同时下载多个大文件

最近学习在Android环境中一些网络请求方面的知识,其中有一部分是关于网络下载方面的知识.在这里解析一下自己写的demo,总结一下自己所学的知识.下图为demo的效果图,仿照一些应用下载商城在ListView中列出加载项,然后可以可以下载和停止. 1.概述 这里有几个比较重要的类DownloadManager.DownloadService.DownloadTask.ThreadDAOImpl.主要的下载流程如下. (1) DownloadManager 负责下载任务的调配,以及下载服务Dow

Android实现多线程断点续传

前言: 项目都快交付阶段了,客户说要改个需求,添加一个断点续传功能.在版本更新,杂志下载或者视频下载的时候实现断点续传.由于时间紧迫,想起了之前研究过一个demo代码,就直接修改使用了,根据自己的方式实现,但是核心代码没变.以后或许会用到,于是就专门写了个demo. 先看一下项目目录结构: db--->操作数据库的(创建数据库表,数据的增删改查.) util--->工具类 download--->实现下载(下载器以及自定义线程.) 这里以易信客户端的下载为例,简要介绍. String d

Android多线程断点续传下载

这个月接到一个项目,要写一个像360助手一样的对于软件管理的APP:其中,遇到了一个问题:多线程断点下载 这个 ,由于之前没有写过这方面的应用功能.所以,不免要自学了.然后就在各个昂站上收索并整理了一下.跟大家分享一下,也能加深我在这方面的理解. 什么是多线程下载? 多线程下载其实就是迅雷,BT一些下载原理,通过多个线程同时和服务器连接,那么你就可以榨取到较高的带宽了,大致做法是将文件切割成N块,每块交给单独一个线程去下载,各自下载完成后将文件块组合成一个文件,程序上要完成做切割和组装的小算法

基于ibcurl的跨平台多线程断点续传下载库

之前写过一个多线程断点续传的下载库,不过那个是基于一个linux的下载程序.windows下运行还好,android下就各种问题,调试起来还麻烦.后面开发游戏的时候,一方面对下载要求不高,另一方面也精力有限,所以就没有继续研究. 趁现在有时间,我希望实现一个自己满意的下载库,满足以下需求: 1.多线程下载,根据文件大小和下载的文件数目进行调度.一般情况下是一个文件一个文件按照顺序下载,如果文件比较多的情况下可以多个文件同时下载,这个是可以设置的. 2.断点续传.下载进度记录到一个配置文件中,要求

Android实现网络多线程断点续传下载(转)

本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多线程断点需要什么功能? 1.多线程下载, 2.支持断点. 使用多线程的好处:使用多线程下载会提升文件下载的速度.那么多线程下载文件的过程是:  (1)首先获得下载文件的长度,然后设置本地文件的长度. HttpURLConnection.getContentLength();//获取下载文件的长度 R

android 多线程断点续传下载 四 - 仿下载助手

我们先一起简单回顾下它的基本原理. http://blog.csdn.net/shimiso/article/details/6763664  android 多线程断点续传下载 一 http://blog.csdn.net/shimiso/article/details/6763986  android 多线程断点续传下载 二 http://blog.csdn.net/shimiso/article/details/8448544  android 多线程断点续传下载 三 界面效果 线程池 T

黑马程序员——Java基础知识之多线程协同

多线程协同 线程间的通讯:对资源的操作动作不同,比如说两个卡车一个拉煤一个装煤,但是他们共享了一个资源. 怎么样把这个资源拿出来?怎样把车装满?这个资源当然是一个类,他里面的组成元素就是对象!!现在我们就要有操作对象的思想了,用对象把这车装满,现在一车装一个对象. 等待唤醒机制: 用的不是sleep是wait.flag标记,这是两人沟通的方式.其实每个标记就要做一次等待或者notify,判断wait,改值notify.线程池.notify唤醒里面的线程,按顺序唤醒.wait和notify必须用在