最近项目需要做一个类似于迅雷的文件下载功能,这类需求可能比较常见,希望可以帮助到有需要的同学

要求:

1.支持断点传输

2. 多文件同时下载

3. 由于是客户内部试用,服务器只支持HTTP文件下载不支持FTP文件(并没有用户权限的要求)

由于根据服务器传来的Json字符串解析后进行下载,首先构建Json对象,推荐一个库Newtonsoft.Json

 public class DownloadFile
{
[JsonProperty("police_num")]
public string PoliceNumber { get; set; } [JsonProperty("equipment_num")]
public string EquipmentNumber { get; set; } [JsonProperty("upload_date")]
public DateTime UploadDateTime { get; set; } [JsonProperty("type")]
public string FileType { get; set; } [JsonProperty("file_name")]
public string FileName { get; set; } [JsonProperty("file_path")]
public string FilePath { get; set; }
}
JsonProperty不区分大小写
public class DownloadTask : ObservableObject
{
/// <summary>
/// </summary>
public static readonly int BufferSize = ; /// <summary>
/// 一次请求大小,每次请求100kb
/// </summary>
public static long Step = *; private int _process; /// <summary>
/// 下载文件参数
/// </summary>
public DownloadFile DownloadFile { get; set; } /// <summary>
/// 下载文件状态
/// </summary>
public SegmentState SegmentState { get; set; } /// <summary>
/// 默认存储路径
/// </summary>
public string DefaultDirectory { get; set; } /// <summary>
/// 当前进度
/// </summary>
public long CurrentSize { get; set; } /// <summary>
/// 文件流对象,用于生成文件
/// </summary>
public FileStream FileStream { get; set; } /// <summary>
/// 下载起始位置
/// </summary>
public long RangeFrom { get; set; } /// <summary>
/// 总大小
/// </summary>
public long TotalSize { get; set; } /// <summary>
/// 链接地址
/// </summary>
public string Url { get; set; } /// <summary>
/// 界面显示进度
/// </summary>
public int Process
{
get { return _process; }
set
{
_process = value;
RaisePropertyChanged("Process");
}
}
}
下载服务类,DownloaderService.cs,功能包括启动下载,暂停,针对文件是否存在进行初始化,获取文件大小方便界面显示
 public class DownloaderService
{ public void OnStart(DownloadTask downloadTask)
{
if (!InitService(downloadTask)) return;
var downloadThread = new Thread(BeginDownloadFile) { IsBackground = true };
downloadThread.Start(downloadTask);
} public void OnStop(DownloadTask downloadTask)
{
downloadTask.SegmentState = SegmentState.Paused;
} private bool InitService(DownloadTask downloadTask)
{
try
{
if (string.IsNullOrEmpty(downloadTask.Url))
{
return false;
} downloadTask.DownloadFile.FileName = downloadTask.Url.Substring(downloadTask.Url.LastIndexOf('/') + ); var fullName = Path.Combine(downloadTask.DefaultDirectory, downloadTask.DownloadFile.FileName); if (File.Exists(fullName))
{
if (downloadTask.TotalSize == )
{
GetTotalSize(downloadTask);
}
if (downloadTask.CurrentSize == downloadTask.TotalSize)
{
if (MessageBox.Show("文件已经存在是否覆盖此文件", "TCL", MessageBoxButton.YesNo, MessageBoxImage.Information) !=
MessageBoxResult.Yes)
return false;
File.Delete(fullName);
downloadTask.CurrentSize = ;
}
downloadTask.FileStream = new FileStream(fullName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
downloadTask.SegmentState = SegmentState.Downloading;
return true;
}
downloadTask.SegmentState = SegmentState.Downloading;
downloadTask.FileStream = new FileStream(fullName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
return true;
}
catch (Exception ex)
{
LogLightConsole.WriteLog(ex.ToString(), EunmMsgType.Error);
return false;
}
} private void BeginDownloadFile(object obj)
{
try
{
var downloadTask = (DownloadTask)obj;
while (true)
{
if (downloadTask.SegmentState == SegmentState.Paused)
{
downloadTask.FileStream.Close();
break;
}
//从0计数,需要减一
var from = downloadTask.CurrentSize;
if (from < )
{
from = ;
} var to = downloadTask.CurrentSize + DownloadTask.Step - ;
if (to >= downloadTask.TotalSize && downloadTask.TotalSize > )
{
to = downloadTask.TotalSize - ;
}
if (downloadTask.TotalSize == )
{
GetTotalSize(downloadTask);
}
if (from >= downloadTask.TotalSize || downloadTask.CurrentSize >= downloadTask.TotalSize)
{
downloadTask.SegmentState = SegmentState.Finished;
downloadTask.FileStream.Close();
downloadTask.Process = ;
return;
} var request = (HttpWebRequest)WebRequest.Create(downloadTask.Url);
//request.Method = "GET";
request.AddRange("bytes", from, to);
request.Timeout = * ;
var response = (HttpWebResponse)request.GetResponse();
var buffer = new byte[];
using (var stream = response.GetResponseStream())
{
if (stream != null)
{
var size = stream.Read(buffer, , buffer.Length);
while (size > )
{
//只将读出的字节写入文件
downloadTask.FileStream.Write(buffer, , size);
downloadTask.CurrentSize += size;
size = stream.Read(buffer, , buffer.Length);
downloadTask.Process = (int)(downloadTask.CurrentSize * / downloadTask.TotalSize);
downloadTask.FileStream.Flush();
}
}
//如果返回的response头中Content-Range值为空,说明服务器不支持Range属性,不支持断点续传,返回的是所有数据
if (response.Headers["Content-Range"] == null)
{
downloadTask.SegmentState = SegmentState.Finished;
}
}
} }
catch (Exception ex)
{
LogLightConsole.WriteLog("BeginDownloadFile" + ex, EunmMsgType.Error);
}
} /// <summary>
/// 获取文件总大小
/// </summary>
public void GetTotalSize(DownloadTask downloadTask)
{
var request = (HttpWebRequest)WebRequest.Create(downloadTask.Url);
//request.Method = "POST";
//request.Headers.Add("charset:" + "utf-8");
request.Timeout = * ;
var response = (HttpWebResponse)request.GetResponse();
downloadTask.TotalSize = response.ContentLength;
}
}

HTTP 1.1版本本身已经扩展了断点传输功能,但是这需要服务器同时也支持,这只是提供了一个简单的例子,具体的针对数据上下文以及成功失败的callback函数,就是做一下委托封装用就好,如果具体使用有什么问题可以私信我,谢谢大家支持!

response.Headers["Content-Range"] == null 说明服务器不支持断点传输

 

基于HTTP的断点传输的更多相关文章

  1. 基于HTTP在互联网传输敏感数据的消息摘要、签名与加密方案

    基于HTTP在互联网传输敏感数据的消息摘要.签名与加密方案 博客分类: 信息安全 Java 签名加密AESMD5HTTPS  一.关键词 HTTP,HTTPS,AES,SHA-1,MD5,消息摘要,数 ...

  2. curl基于URL的文件传输工具

    简介 cURL是一款开源的基于URL的文件传输工具,支持HTTP.HTTPS.FTP等协议,支持POST.cookie.认证.扩展头部.限速等特性. curl命令用途广泛,比如下载.发送http请求. ...

  3. C# Socket服务端与客户端通信(包含大文件的断点传输)

    步骤: 一.服务端的建立 1.服务端的项目建立以及页面布局 2.各功能按键的事件代码 1)传输类型说明以及全局变量 2)Socket通信服务端具体步骤:   (1)建立一个Socket   (2)接收 ...

  4. 基于epoll的TP传输层实现

    1. 抽象TP传输层设计 在使用epoll实现实际的传输层之前,先设计一个抽象的传输层,这个抽象的传输层是传输层实现的接口层. 接口层中一共有以下几个通用的类或者接口: (1)Socket:通用的套接 ...

  5. 基于SSL的WCF传输安全

    [实践]WCF传输安全1:前期准备之证书制作   [实践]WCF传输安全2:基于SSL的WCF匿名客户端   [实践]WCF传输安全3:基于SSL的WCF对客户端验证   [实践]WCF传输安全4:基 ...

  6. 基于网站地址URL传输session信息

    在php的学习中,会话是我们常常用到的,那今天我们就来详细讲讲会话中的session: 一.session的工作机制:当开启session后,服务器会在服务器中保存session文件,然后再浏览器保存 ...

  7. 基于TCP的字符串传输程序

    ---恢复内容开始--- LINUX中的网络编程是通过SOCKET接口来进行的. Socket(套接字) Socket相当于进行网络通信两端的插座,只要对方的Socket和自己的Socket有通信联接 ...

  8. 基于选择重传ARQ传输协议的数据重传机制方案设计

    原文链接: http://blog.csdn.net/pinghegood/article/details/7841281  1.背景 最近在项目中,由于使用TD网络传输数据,数据掉包严重,软件组老大 ...

  9. 基于socket的udp传输,socketserver模块,进程

    基于UDP的套接字 udp是无连接的,先启动哪一端都不会报错 socket.SOCK_DGRAM 数据报协议 udp不会发送空数据,什么都不输入直接发送也会有报头发过去 服务端 import sock ...

随机推荐

  1. 谈谈一些有趣的CSS题目(十一)-- reset.css 知多少?

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  2. 旺财速啃H5框架之Bootstrap(四)

    上一篇<<旺财速啃H5框架之Bootstrap(三)>>已经把导航做了,接下来搭建内容框架.... 对于不规整的网页,要做成自适应就有点玩大了.... 例如下面这种版式的页面. ...

  3. CSS Position 定位属性

    本篇文章主要介绍元素的Position属性,此属性可以设置元素在页面的定位方式. 目录 1. 介绍 position:介绍position的值以及辅助属性. 2. position 定位方式:介绍po ...

  4. FILE文件流的中fopen、fread、fseek、fclose的使用

    FILE文件流用于对文件的快速操作,主要的操作函数有fopen.fseek.fread.fclose,在对文件结构比较清楚时使用这几个函数会比较快捷的得到文件中具体位置的数据,提取对我们有用的信息,满 ...

  5. (转)从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群)

    原文地址:  http://www.cnblogs.com/lyhabc/p/4682028.html 这一篇是从0开始搭建SQL Server AlwaysOn 的第二篇,主要讲述如何搭建故障转移集 ...

  6. Linux硬件IO的优化简介

    Linux硬件IO的优化简介 首先简单介绍下有哪些硬件设备如下(由于硬件种类厂家等各种因素我就不在此多做介绍有兴趣的可以自行学习): 1.CPU:中央处理器,是计算机运算控制的核心部件之一,相当于人的 ...

  7. (整理)MyBatis入门教程(一)

    本文转载: http://www.cnblogs.com/hellokitty1/p/5216025.html#3591383 本人文笔不行,根据上面博客内容引导,自己整理了一些东西 首先给大家推荐几 ...

  8. 挑子学习笔记:两步聚类算法(TwoStep Cluster Algorithm)——改进的BIRCH算法

    转载请标明出处:http://www.cnblogs.com/tiaozistudy/p/twostep_cluster_algorithm.html 两步聚类算法是在SPSS Modeler中使用的 ...

  9. 一个无限加载瀑布流jquery实现

    实现大概是下面的效果,写了比较详细的注释 <!DOCTYPE html><html> <head> <meta charset="UTF-8&quo ...

  10. 您真的理解了SQLSERVER的日志链了吗?

    您真的理解了SQLSERVER的日志链了吗? 先感谢宋沄剑给本人指点迷津,还有郭忠辉童鞋今天在QQ群里抛出的问题 这个问题跟宋沄剑讨论了三天,再次感谢宋沄剑 一直以来,SQLSERVER提供了一个非常 ...