C# 文件下载之断点续传实现代码

注意,本文所说的断点续传特指 HTTP 协议中的断点续传。本文主要聊聊思路和关键代码,更多细节请参考本文附带的 demo。

工作原理

HTTP 协议中定义了一些请求/响应头,通过组合使用这些头信息。我们可以在一次 HTTP 请求中只请求一个文件中的一部分数据。这样我们就可以把已经下载的数据存起来,下次只用请求剩余的数据即可,当全部数据都下载到本地后再完成合并工作。

HTTP 协议指出,可以通过 HTTP 请求中的 Range 头指定请求数据的范围,Range 头的使用也很简单,只要指定下面的格式就可以了:

Range: bytes=500-999

它的意思是,只请求目标文件的第 500 到第 999 这 500 个字节。

比如我有一个1000 bytes 大小的文件需要下载,第一次请求时不用指定 Range 头,表示下载整个文件。但在下载完第 499 个字节后,下载被取消了。那么在下一次请求下载同一个文件时,只需要下载第 500 个字节至第 999 个字节的数据就可以了。原理看上去很简单,但我们需要考虑下面几个问题:

1.是不是所有的 web 服务器都支持 Range 头?

2.多次请求之间可能会间隔很长的时间,服务器上的文件发生了变化怎么办?

3.如何保存下载的部分数据和相关信息?

4.当我们通过字节操作把一个文件拼成原始大小后,如何验证它和源文件一模一样?

下面我们就带着这些问题去探究断点续传的一些细节。

检查服务器端对断点续传的支持

在服务器响应我们的请求时,会在响应头中通过 Accept-Ranges 指明是否接受请求一个资源的一部分数据。但这里似乎有个小小的陷阱,就是不同的服务器可能返回不同的值来指明自己能够接受部分资源的请求。貌似比较统一的方法是,当服务器不支持请求部分数据时,都会返回 Accept-Ranges: none,我们只要判断这个返回值是不是等于 none 就行了。代码如下:

private static bool IsAcceptRanges(WebResponse res)
{
  if (res.Headers["Accept-Ranges"] != null)
  {
    string s = res.Headers["Accept-Ranges"];
    if (s == "none")
    {
      return false;
    }
  }
  return true;
}

检查服务器端文件是否变化

当我们下载了一个文件的一部分之后,可能马上就会接着下载,也可能会过一段时间再下载,也可能永远不会再接着下载了…
这里的问题是,当下次要接着下载时,如何确定服务器上的文件还是当初下载了一半的那个文件。如果服务器上的文件已经更新了,那无论如何都需要重新从头开始下载。只有在服务器上的文件没有发生变化的情况下,断点续传才有意义。
对于这个问题,HTTP 响应头为我们提供了不同的选择。ETag 和 Last-Modified 都能完成任务。

先看 ETag:

The ETag response-header field provides the current value of the entity tag for the requested variant. (引自RFC2616 14.19 ETag)

简单点说 ETag 就是一个标识当前请求内容的字符串,当请求的资源发生变化后,对应的 ETag 也会变化。好了,最简单的办法是第一次请求时,把响应头中的 ETag 存下来,下次请求时做比较。代码如下:

string newEtag = GetEtag(response);
// tempFileName指已经下载到本地的部分文件内容
// tempFileInfoName指保存了Etag内容的临时文件
if (File.Exists(tempFileName) && File.Exists(tempFileInfoName))
{
  string oldEtag = File.ReadAllText(tempFileInfoName);
  if (!string.IsNullOrEmpty(oldEtag) && !string.IsNullOrEmpty(newEtag) && newEtag == oldEtag)
  {
  // Etag没有变化,可以断点续传
    resumeDowload = true;
  }
}
else
{
  if (!string.IsNullOrEmpty(newEtag))
  {
    File.WriteAllText(tempFileInfoName, newEtag);
  }
}
private static string GetEtag(WebResponse res)
{
  if (res.Headers["ETag"] != null)
  {
    return res.Headers["ETag"];
  }
  return null;
}

再来看看 Last-Modified:

The Last-Modified entity-header field indicates the date and time at which the origin server believes the variant was last modified. (引自RFC2616 14.29 Last-Modified)

Last-Modified 就是所请求的资源在服务器上的最后一次修改时间。使用方法和 ETag 大体相同。

个人感觉使用 ETag 和 Last-Modified 中的任何一个都能达到我们的目的。但是你也可以两个都用,做 double check,谁知道web服务器的实现是不是严格遵循了 HTTP 协议!

保存中间结果

这里主要就是用 C# 进行文件操作。大体思路是如果有未下载完的文件,就把新下载的字节添加到文件的末尾,不再啰嗦,有兴趣的同学请直接看 demo 代码。

验证文件

在断点续传的过程中,我们以 byte 为单位下载、合并文件,如果整个过程中稍有没有处理好的异常,可能最后得到的文件就和源文件不太一样。因此最好是能够对下载好的文件进行一次校验。可这也是最难、最不容易实现的。因为它需要服务器端的支持,比如服务器端在提供一个可下载文件的同时提供该文件的 MD5 hash。当然,如果服务器端也是我们自己创建的,我们就可以去实现它。但我们又怎么能够要求现存的 web 服务器都提供这样的功能呢!

Demo 下载

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • asp.net(c#)文件下载实现代码

    复制代码 代码如下: using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; usi

  • C#实现word文件下载的代码

    效果: 思路: 简单的有两种方式下载,一种是流下载,一种是WriteFile下载.以下是使用WriteFile下载. 代码: 复制代码 代码如下: protected void LinkButton1_Click(object sender, EventArgs e)        {            try            {                //WriteFile实现下载(word)                string fileName = "qingpin

  • C#中WebClient实现文件下载

    鉴于各种复杂的网络环境,笔者决定采用不同的编程接口进行下载尝试,以增加程序的可用性. 这里仅介绍使用 WebClient 的方法,后续的文章会介绍其他的方法.博文中主要介绍思路和关键代码,完整的 demo 附在文末. 使用代理访问网络 很多公司的员工都是通过公司设置的代理上网的.通过代理上网主要是方便公司进行各种的管制,当然也能实现一些特殊的功能- 不过这会给我们的程序访问网络带来一些问题. 其实,WebClient 中的 API 已经很智能了,比如我们创建的 HttpWebRequest 对象

  • C#文件下载实例代码(适用于各个浏览器)

    1.cs代码 public void DownFile(string filePath ,string fileName ) { // filePath 文件路径 例如:/File/记录.xlsx // fileName 文件名称 例如:记录.xlsx (要后缀哦) Encoding encoding; // 申明编码 string outputFileName; // 输出名字 Debug.Assert(HttpContext.ApplicationInstance.Request.UserA

  • c#文件下载示例的4种方法分享

    复制代码 代码如下: using System;using System.Data;using System.Configuration;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Web.UI.HtmlControls;using System

  • C# 文件下载之断点续传实现代码

    注意,本文所说的断点续传特指 HTTP 协议中的断点续传.本文主要聊聊思路和关键代码,更多细节请参考本文附带的 demo. 工作原理 HTTP 协议中定义了一些请求/响应头,通过组合使用这些头信息.我们可以在一次 HTTP 请求中只请求一个文件中的一部分数据.这样我们就可以把已经下载的数据存起来,下次只用请求剩余的数据即可,当全部数据都下载到本地后再完成合并工作. HTTP 协议指出,可以通过 HTTP 请求中的 Range 头指定请求数据的范围,Range 头的使用也很简单,只要指定下面的格式

  • python 文件下载之断点续传的实现

    目录 1.前序 2.技术原理 2.1 Content-Range 2.2 Range 3. 代码实现 1.前序 当下载突然断开后,断点续传就需要了,继续前面下载的内容下载.解决了不需要重复下载 2.技术原理 HTTP/1.1 开始支持断点续传,一般断点下载会用到 Range 和 Content-Range 实体头 Range是请求头,Content-Range是响应头 2.1 Content-Range 用于响应头中 语法: Content-Length: <length> 2.2 Range

  • RxJava+Retrofit+OkHttp实现多文件下载之断点续传

    背景 断点续传下载一直是移动开发中必不可少的一项重要的技术,同样的Rxjava和Retrofit的结合让这个技术解决起来更加的灵活,我们完全可以封装一个适合自的下载框架,简单而且安全! 效果 实现 下载和之前的http请求可以相互独立,所以我们单独给download建立一个工程moudel处理 1.创建service接口 和以前一样,先写接口 注意:Streaming是判断是否写入内存的标示,如果小文件可以考虑不写,一般情况必须写:下载地址需要通过@url动态指定(不适固定的),@head标签是

  • ASP.NET 文件断点续传实现代码

    这里我通过Response类中的AddHeader方法将一个HTTP头添加到输出流中.在HTTP头中,是由头信息和体信息组成.两者之间用一行空行分开.这里利用在头中加入Range段,来表示客户端希望从何处继续下载,来实现续传功能. 好了废话不多说,让我们开始吧. 1.新建1个主页,名字随便起哈. 2.在该页中添加1个LinkButton按钮,该按钮用来执行实现的过程. 3.在LinkButton的Click事件中,实现断点续传功能. 代码如下: 另外不要忘记引用System.IO命名空间,这里只

  • Golang Gin框架实现文件下载功能的示例代码

    目录 Layui框架实现文件上传 Gin框架获取前端上传的文件 Gin框架的文件下载 Layui框架实现文件上传 基本的思路就是随便创建一个元素,然后使用layui的upload组件对创建的元素进行渲染,详见代码 <!DOCTYPE html> <html lang="en"> <head> <script src="jquery-3.5.0.min.js" type="text/javascript"&

  • asp.net中文件下载功能的实例代码

    复制代码 代码如下: //TransmitFile实现下载protected void Button1_Click(object sender, EventArgs e){ Response.ContentType = "application/x-zip-compressed";Response.AddHeader("Content-Disposition", "attachment;filename=z.zip");string filena

  • PHP 强制性文件下载功能的函数代码(任意文件格式)

    复制代码 代码如下: /******************** *@file - path to file */ function force_download($file) { if ((isset($file))&&(file_exists($file))) { header("Content-length: ".filesize($file)); header('Content-Type: application/octet-stream'); header('

  • PHP实现文件下载断点续传详解

    如果我们的网站提供文件下载的服务,那么通常我们都希望下载可以断点续传(Resumable Download),也就是说用户可以暂停下载,并在未来的某个时间从暂停处继续下载,而不必重新下载整个文件. 通常情况下,Web服务器(如Apache)会默认开启对断点续传的支持.因此,如果直接通过Web服务器来提供文件的下载,可以不必做特别的配置,即可享受到断点续传的好处.由于这些文件直接通过Web服务器来提供下载,后端脚本无法对这个下载过程进行控制.这对于仅提供公开.静态文件的网站来说不是问题,但对于需要

  • C#怎样实现文件下载断点续传

    前言 老规矩,还是从最简单粗暴的开始.那么多简单算简单?多粗暴算粗暴?我告诉你可以不写一句代码,你信吗?直接把一个文件往IIS服务器上一扔,就支持下载.还TM么可以断点续传(IIS服务端默认支持). 在贴代码之前先来了解下什么是断点续传(这里说的是下载断点续传)?怎么实现的断点续传? 断点续传就是下载了一半断网或者暂停了,然后可以接着下载.不用从头开始下载. 很神奇吗,其实简单得很,我们想想也是可以想到的. 首先客户端向服务端发送一个请求(下载文件).然后服务端响应请求,信息包含文件总大小.文件

  • Android文件下载功能实现代码

    本文实例为大家分享了Android文件下载功能的具体代码,供大家参考,具体内容如下 1.普通单线程下载文件: 直接使用URLConnection.openStream()打开网络输入流,然后将流写入到文件中! public static void downLoad(String path,Context context)throws Exception { URL url = new URL(path); InputStream is = url.openStream(); //截取最后的文件名

随机推荐