一、前言

网上有许多的多线程断点续传操作,但总是写的很云里雾里,或者写的比较坑长。由于这几个月要负责公司的在线升级项目,所以正好顺便写了一下

代码如下:

 using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks; namespace TestCenter
{
class Program
{
static void Main(string[] args)
{
string LocalSavePath = @"E:\Test\TestFile\Local\1.msi"; //本地目标文件路径 FileInfo SeverFilePath = new FileInfo(@"E:\Test\TestFile\Server\1.msi"); //服务器待文件路径
long FileLength = SeverFilePath.Length; //待下载文件大小 Console.WriteLine("Start Configuration");
int PackCount = ; //初始化数据包个数 long PackSize = ; //数据包大小 if (FileLength % PackSize > )
{
PackCount = (int)(FileLength / PackSize) + ;
} else
{
PackCount = (int)(FileLength / PackSize);
} Console.WriteLine("Start Recieve");
var tasks = new Task[PackCount]; //多线程任务 for (int index = ; index < PackCount; index++)
{ int Threadindex = index; //这步很关键,在Task()里的绝对不能直接使用index
var task = new Task(() =>
{
string tempfilepath = @"E:\Test\TestFile\Temp\" + "QS_" + Threadindex + "_" + PackCount; //临时文件路径 using (FileStream tempstream = new FileStream(tempfilepath, FileMode.Create, FileAccess.Write, FileShare.Write))
{
int length = (int)Math.Min(PackSize, FileLength - Threadindex * PackSize); var bytes = GetFile(Threadindex*PackCount, length); tempstream.Write(bytes, , length);
tempstream.Flush();
tempstream.Close();
tempstream.Dispose();
}
});
tasks[Threadindex] = task;
task.Start();
} Task.WaitAll(tasks); //等待所有线程完成
Console.WriteLine("Recieve End"); //检测有哪些数据包未下载
Console.WriteLine("Start Compare");
DirectoryInfo TempDir = new DirectoryInfo(@"E:\Test\TestFile\temp"); //临时文件夹路径
List<string> Comparefiles = new List<string>(); for (int i = ; i < PackCount; i++)
{
bool hasfile = false;
foreach (FileInfo Tempfile in TempDir.GetFiles())
{
if (Tempfile.Name.Split('_')[] == i.ToString())
{
hasfile = true;
break;
}
}
if (hasfile == false)
{
Comparefiles.Add(i.ToString());
}
} //最后补上这些缺失的文件
if (Comparefiles.Count > )
{
foreach (string com_index in Comparefiles)
{
string tempfilepath = @"E:\Test\TestFile\Temp\" + "QS_" + com_index+ "_" + PackCount;
using (FileStream Compstream = new FileStream(tempfilepath, FileMode.Create, FileAccess.Write, FileShare.Write))
{
int length = (int)Math.Min(PackSize, FileLength - Convert.ToInt32(com_index) * PackSize);
var bytes = GetFile(Convert.ToInt32(com_index)*PackCount, length);
Compstream.Write(bytes, , length);
Compstream.Flush();
Compstream.Close();
Compstream.Dispose();
}
} }
Console.WriteLine("Compare End"); //准备将临时文件融合并写到1.msi中
Console.WriteLine("Start Write");
using (FileStream writestream = new FileStream(LocalSavePath, FileMode.Create, FileAccess.Write, FileShare.Write))
{
foreach (FileInfo Tempfile in TempDir.GetFiles())
{
using (FileStream readTempStream = new FileStream(Tempfile.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
long onefileLength = Tempfile.Length;
byte[] buffer = new byte[Convert.ToInt32(onefileLength)];
readTempStream.Read(buffer, , Convert.ToInt32(onefileLength));
writestream.Write(buffer, , Convert.ToInt32(onefileLength));
}
}
writestream.Flush();
writestream.Close();
writestream.Dispose();
}
Console.WriteLine("Write End"); //删除临时文件
Console.WriteLine("Start Delete Temp Files");
foreach (FileInfo Tempfile in TempDir.GetFiles())
{
Tempfile.Delete();
}
Console.WriteLine("Delete Success");
Console.ReadKey();
} //这个方法可以放到Remoting或者WCF服务中去,然后本地调用该方法即可实现多线程断点续传
public static byte[] GetFile(int start, int length)
{
string SeverFilePath = @"E:\Test\TestFile\Server\1.msi";
using (FileStream ServerStream = new FileStream(SeverFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, *, true))
{
byte[] buffer = new byte[length];
ServerStream.Position = start;
//ServerStream.Seek(start, SeekOrigin.Begin);
ServerStream.Read(buffer, , length);
return buffer;
}
}
}
}

二、讨论

1)需要注意的是第44行,不能直接使用index变量在Task()里进行操作,而是要将它赋给Threadindex,让Threadindex在Task()里,不然会直接报错,为什么呢?

链接:http://bbs.csdn.net/topics/390769774

2)70至108行代码可以在外面再套一层while循环,循环检测临时文件是否下完整了,然后再定义一个检测最大上限,超过这个上限就放弃本次更新,当用户的网络恢复正常后下次再做更新操作。所以说放临时文件的文件夹最好要包含版本信息,不会把2.0.0的临时文件和1.0.0的临时文件搞混。

3) FileStream.Position 与 FileStream.Seek(long offset, SeekOrigin seekorigin) 的作用都是获取流的指针位置,当文件路径使用绝对路径时使用Position;相对路径时使用Seek方法

链接:https://stackoverflow.com/questions/7238929/stream-seek0-seekorigin-begin-or-position-0

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

  1. FileStream实现多线程断点续传(已封装)

    处理文件分片 处理缺失的分片文件 合并分片文件 MD5验证文件 using System; using System.Collections.Generic; using System.IO; usi ...

  2. AsyncTask实现多任务多线程断点续传下载

    这篇博客是AsyncTask下载系列的最后一篇文章,前面写了关于断点续传的和多线程下载的博客,这篇是在前两篇的基础上面实现的,有兴趣的可以去看下. 一.AsyncTask实现断点续传 二.AsyncT ...

  3. Java入门到精通——基础篇之多线程实现简单的PV操作的进程同步

    Java入门到精通——基础篇之多线程实现简单的PV操作的进程同步 一.概述     PV操作是对信号量进行的操作.     进程同步是指在并发进程之间存在一种制约关系,一个进程的执行依赖另一个进程的消 ...

  4. 实现android支持多线程断点续传下载器功能

    多线程断点下载流程图: 多线程断点续传下载原理介绍: 在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度手机端下载数据时难免会出现无信号断线.电量不足等情况,所以需要断点续传功能根据下 ...

  5. android 多线程断点续传下载

    今天跟大家一起分享下Android开发中比较难的一个环节,可能很多人看到这个标题就会感觉头很大,的确如果没有良好的编码能力和逻辑思维,这块是很难搞明白的,前面2次总结中已经为大家分享过有关技术的一些基 ...

  6. Android开发多线程断点续传下载器

    使用多线程断点续传下载器在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度,在下载过程中记录每个线程已拷贝数据的数量,如果下载中断,比如无信号断线.电量不足等情况下,这就需要使用到断点 ...

  7. Android多线程断点续传下载

    这个月接到一个项目.要写一个像360助手一样的对于软件管理的APP:当中.遇到了一个问题:多线程断点下载 这个 ,因为之前没有写过这方面的应用功能.所以.不免要自学了. 然后就在各个昂站上收索并整理了 ...

  8. Java基础教程:多线程基础(1)——基础操作

    Java:多线程基础(1) 实现多线程的两种方式 1.继承Thread类 public class myThread extends Thread { /** * 继承Thread类,重写RUN方法. ...

  9. Java基础教程:多线程基础(4)——Lock的使用

    Java基础教程:多线程基础(4)——Lock的使用 快速开始 Java 5中Lock对象的也能实现同步的效果,而且在使用上更加方便. 本节重点的2个知识点是:ReentrantLock类的使用和Re ...

随机推荐

  1. Python黑帽编程2.2 数值类型

    Python黑帽编程2.2  数值类型 数值类型,说白了就是处理各种各样的数字,Python中的数值类型包括整型.长整型.布尔.双精度浮点.十进制浮点和复数,这些类型在很多方面与传统的C类型有很大的区 ...

  2. MySql.Data.MySqlClient.MySqlException: Parameter ‘@maxid’ must be defined

    本文涉及到的mysql知识点: mysql中的if条件语句用法: IF(expr1,expr2,expr3) mysql使用变量(mysql中变量不用事前申明) mysql事务 testcase 为了 ...

  3. spring mvc Error instantiating class ** with invalid types () or values (). Cause: java.lang.NoSuchMethodException:

    一般引起这种问题的原因是 bean和mapper里面的字段未对应上,或者 bean里面没有默认的构造函数引起的.我今天是后面的一个,自己写了带参数的构造函数引起的这个问题...

  4. Red Gate(SQLToolbelt)SQL Server的安装与注册(破解)

    Red Gate(SQLToolbelt)是SQL Server辅佐工具 1.SQL Compare 比较和同步SQL Server数据库结构 2.SQL Data Compare 比较和同步SQL ...

  5. Azure Service Febric 笔记:Web API应用

    1.什么是Service Febric 贴一段微软官方的介绍 Service Fabric 是一种分布式系统平台,可让你轻松打包.部署和管理可缩放.可靠的微服务.Service Fabric 还解决了 ...

  6. Constraint6:更新外键约束(Foreign Key Constraint)的引用列

    在SQL Server中,表之间存在引用关系,引用关系通过创建外键约束(Foreign Key Constraint)实现.如果一个Table中的column被其他Table引用,那么该表是参考表,或 ...

  7. IIS7.5+WebConfig实现页面伪静态和301重定向

    IIS7.5+WebConfig实现页面伪静态和301重定向 使用URLRewriter组件在windows 2003 +iis 6.0下配置伪静态的文章网络上一大堆.但在iis7.0或iis 7.5 ...

  8. C#设计模式系列:状态模式(State)

    1.状态模式简介 1.1>.定义 状态模式的核心思想是允许一个对象在它的内部状态改变时改变它的行为,即不同的状态对应不同的行为. 状态模式的针对性很强,当有状态变化的时候可以选择状态模式. 1. ...

  9. 在浏览器中输入URL按下回车键后发生了什么

    在浏览器中输入URL按下回车键后发生了什么 [1]解析URL[2]DNS查询,解析域名,将域名解析为IP地址[3]ARP广播,根据IP地址来解析MAC地址[4]分别从应用层到传输层.网络层和数据链路层 ...

  10. ASP.NET中使用HttpWebRequest调用WCF

    最近项目需要和第三网站进行数据交换,第三方网站基本都是RESTfull形式的API,但是也有的是Web Service,或者.NET里面的WCF.微软鼓励大家使用WCF替代Web Service. W ...