一、前言

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

代码如下:

 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. Android图片资源

    title: 2016-5-5未命名文件 tags: UI适配,图片资源 grammar_cjkRuby: true --- 概述: 本文整理了Android开发中,图片资源的提供方式和使用方式.包括 ...

  2. ASP.NET Core 数据保护(Data Protection)【上】

    前言 上一篇博客记录了如何在 Kestrel 中使用 HTTPS(SSL), 也是我们目前项目中实际使用到的. 数据安全往往是开发人员很容易忽略的一个部分,包括我自己.近两年业内也出现了很多因为安全问 ...

  3. .NET中XML序列化的总结

    [题外话] 以前虽然常用.NET中的序列化,但是常用的BinaryFormatter,也就是二进制文件的序列化,却鲜用XML的序列化.对于XML序列化,.NET中同样提供了一个非常方便的工具XmlSe ...

  4. ASP.NET Web API路由系统:Web Host下的URL路由

    ASP.NET Web API提供了一个独立于执行环境的抽象化的HTTP请求处理管道,而ASP.NET Web API自身的路由系统也不依赖于ASP.NET路由系统,所以它可以采用不同的寄宿方式运行于 ...

  5. 机器学习理论知识部分--偏差方差平衡(bias-variance tradeoff)

    摘要: 1.常见问题 1.1 什么是偏差与方差? 1.2 为什么会产生过拟合,有哪些方法可以预防或克服过拟合? 2.模型选择例子 3.特征选择例子 4.特征工程与数据预处理例子 内容: 1.常见问题 ...

  6. Gitcafe绑定自定义域名

    之前将自己练习写作工具替换为Markdown,部署工具改为Hexo,并且将托管地搬家到GitCafe之后,便是被各种的舒爽所围绕.具体折腾的详情参见使用Hexo搭建专属Blog.她们的组合方便快捷,让 ...

  7. angularjs 2.0 快速案例(1)

    前言 上一节我们已经把环境给搭建起来了,现在我们通过一个快速案例把angular 2.0 初步了解一下,后续我们会深入每一个细节,这个案例主要是一个[英雄(Hero)]列表的展示,创建,编辑.这个案例 ...

  8. C#设计模式-模板方法模式

    提到模板,大家肯定不免想到生活中的“简历模板”.“论文模板”.“Word中模版文件”等,在现实生活中,模板的概念就是——有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简历模板,下 ...

  9. removeClass 按钮点击添加class效果

    html代码: <div class="game"> <span class="active">全部</span> < ...

  10. Windows下搭建MySQL Master Slave

    一.背景 服务器上放了很多MySQL数据库,为了安全,现在需要做Master/Slave方案,因为操作系统是Window的,所以没有办法使用keepalived这个HA工具,但是我们可以接受人工进行切 ...