一、前言

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

代码如下:

 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. window下搭建c开发环境(GNU环境的安装)

    一.在windows平台上安装GNU环境 windows操作系统不自带GNU环境,如果需要开发跨平台的C语言程序,那么需要给windows安装GNU环境 windows下的两款GNU环境:MinGW和 ...

  2. 跨平台网络抓包工具-Microsoft Message Analyzer

    Microsoft Message Analyzer (MMA 2013)是微软最受欢迎的Netmon的最新版本. 在Netmon网络跟踪和排除故障功能的基础上提供了更强大的跨平台网络分析追踪能力.园 ...

  3. Android安全开发之浅谈密钥硬编码

    Android安全开发之浅谈密钥硬编码 作者:伊樵.呆狐@阿里聚安全 1 简介 在阿里聚安全的漏洞扫描器中和人工APP安全审计中,经常发现有开发者将密钥硬编码在Java代码.文件中,这样做会引起很大风 ...

  4. Python黑帽编程 2.0 第二章概述

    Python黑帽编程 2.0 第二章概述 于 20世纪80年代末,Guido van Rossum发明了Python,初衷据说是为了打发圣诞节的无趣,1991年首次发布,是ABC语言的继承,同时也是一 ...

  5. Chrome 控制台新玩法-console显示图片以及为文字加样式

    有兴趣的同学可以文章最后的代码复制贴到控制台玩玩. Go for Code 在正常模式下,一般只能向console 控制台输出简单的文字信息.但为了把信息输出得更优雅更便于阅读,除了cosole.lo ...

  6. Wakatime 测试工作时间

    Wakatime – 现在几点了,你在做什么呢 前面提到了一个用来QS自己的工具Clarify.这次介绍一个专门给程序员用的工具.大家都知道一万小时定律,但我究竟写java写了多久了呢?WakaTim ...

  7. JSP的基本语法

    JSP的基本语法 一.JSP页面中的JAVA代码 二.JSP页面中的指令 三.JSP页面中的隐含对象(九大内置对象) 目录 一.JSP页面中的JAVA代码 JSP表达式(方便输出) JSP小脚本(完成 ...

  8. php解决中文截取乱码问题

    针对截取字符串出现中文乱码问题,网上有很多介绍,也有很多函数,但笔者看着网上的函数,总感觉有点别扭, 所以自己动手写了一个防止截取字符串时出现中文乱码的函数. 实现的原理还是比较简单,主要是利用ASC ...

  9. SSIS 数据源组件的External Metadata和Advanced Property

    1,SSIS的组件属性ValidateExternalMetadata 如果一个Destination组件使用的是上游创建的staging table,那么必须设置 ValidateExternalM ...

  10. 群福利:百度云管家-本地SVIP

    效果 如果不想登录破解版的百度云(防止泄密)==>复制AppSettingApp.dat和users文件夹,这样你就可以免登录了 最稳定版本:https://yunpan.cn/cBTQc9Iu ...