使用 C# 下载文件的多种方法小结

目录
  • 简单下载
  • 异步下载
  • 下载文件的同时向服务器发送自定义请求头
  • 如何解决下载文件不完整的问题
  • 使用 Downloader 进行 HTTP 多线程下载
  • 下载非 HTTP 协议的文件

文件下载是一个软件开发中的常见需求。本文从最简单的下载方式开始步步递进,讲述了文件下载过程中的常见问题并给出了解决方案。并展示了如何使用多线程提升 HTTP 的下载速度以及调用 aria2 实现非 HTTP 协议的文件下载。

简单下载

在 .NET 程序中下载文件最简单的方式就是使用 WebClient 的 DownloadFile 方法:

 var url = "https://www.coderbusy.com";
    var save = @"D:\1.html";
    using (var web = new WebClient())
    {
        web.DownloadFile(url,save);
    }

异步下载

该方法也提供异步的实现:

 var url = "https://www.coderbusy.com";
    var save = @"D:\1.html";
    using (var web = new WebClient())
    {
        await web.DownloadFileTaskAsync(url, save);
    }

下载文件的同时向服务器发送自定义请求头

如果需要对文件下载请求进行定制,可以使用 HttpClient :

var url = "https://www.coderbusy.com";
    var save = @"D:\1.html";
    var http = new HttpClient();
    var request = new HttpRequestMessage(HttpMethod.Get,url);
    //增加 Auth 请求头
    request.Headers.Add("Auth","123456");
    var response = await http.SendAsync(request);
    response.EnsureSuccessStatusCode();
    using (var fs = File.Open(save, FileMode.Create))
    {
        using (var ms = response.Content.ReadAsStream())
        {
            await ms.CopyToAsync(fs);
        }
    }

如何解决下载文件不完整的问题

以上所有代码在应对小文件的下载时没有特别大的问题,在网络情况不佳或文件较大时容易引入错误。以下代码在开发中很常见:

  var url = "https://www.coderbusy.com";
    var save = @"D:\1.html";
    if (!File.Exists(save))
    {
        Console.WriteLine("文件不存在,开始下载...");
        using (var web = new WebClient())
        {
            await web.DownloadFileTaskAsync(url, save);
        }
        Console.WriteLine("文件下载成功");
    }
    Console.WriteLine("开始处理文件");
    //TODO:对文件进行处理

如果在 DownloadFileTaskAsync 方法中发生了异常(通常是网络中断或网络超时),那么下载不完整的文件将会保留在本地系统中。在该任务重试执行时,因为文件已存在(虽然它不完整)所以会直接进入处理程序,从而引入异常。

一个简单的修复方式是引入异常处理,但这种方式对应用程序意外终止造成的文件不完整无效:

 var url = "https://www.coderbusy.com";
    var save = @"D:\1.html";
    if (!File.Exists(save))
    {
        Console.WriteLine("文件不存在,开始下载...");
        using (var web = new WebClient())
        {
            try
            {
                await web.DownloadFileTaskAsync(url, save);
            }
            catch
            {
                if (File.Exists(save))
                {
                    File.Delete(save);
                }
                throw;
            }
        }
        Console.WriteLine("文件下载成功");
    }
    Console.WriteLine("开始处理文件");
    //TODO:对文件进行处理

笔者更喜欢的方式是引入一个临时文件。下载操作将数据下载到临时文件中,当确定下载操作执行完毕时将临时文件改名:

var url = "https://www.coderbusy.com";
    var save = @"D:\1.html";
    if (!File.Exists(save))
    {
        Console.WriteLine("文件不存在,开始下载...");
        //先下载到临时文件
        var tmp = save + ".tmp";
        using (var web = new WebClient())
        {
            await web.DownloadFileTaskAsync(url, tmp);
        }
        File.Move(tmp, save, true);
        Console.WriteLine("文件下载成功");
    }
    Console.WriteLine("开始处理文件");
    //TODO:对文件进行处理

使用 Downloader 进行 HTTP 多线程下载

在网络带宽充足的情况下,单线程下载的效率并不理想。我们需要多线程和断点续传才可以拿到更好的下载速度。

Downloader 是一个现代化的、流畅的、异步的、可测试的和可移植的 .NET 库。这是一个包含异步进度事件的多线程下载程序。Downloader 与 .NET Standard 2.0 及以上版本兼容,可以在 Windows、Linux 和 macOS 上运行。

GitHub 开源地址: https://github.com/bezzad/Downloader

NuGet 地址:https://www.nuget.org/packages/Downloader

从 NuGet 安装 Downloader 之后,创建一个下载配置:

 var downloadOpt = new DownloadConfiguration()
    {
        BufferBlockSize = 10240, // 通常,主机最大支持8000字节,默认值为8000。
        ChunkCount = 8, // 要下载的文件分片数量,默认值为1
        MaximumBytesPerSecond = 1024 * 1024, // 下载速度限制为1MB/s,默认值为零或无限制
        MaxTryAgainOnFailover = int.MaxValue, // 失败的最大次数
        OnTheFlyDownload = false, // 是否在内存中进行缓存? 默认值是true
        ParallelDownload = true, // 下载文件是否为并行的。默认值为false
        TempDirectory = "C:\\temp", // 设置用于缓冲大块文件的临时路径,默认路径为Path.GetTempPath()。
        Timeout = 1000, // 每个 stream reader  的超时(毫秒),默认值是1000
        RequestConfiguration = // 定制请求头文件
        {
            Accept = "*/*",
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
            CookieContainer =  new CookieContainer(), // Add your cookies
            Headers = new WebHeaderCollection(), // Add your custom headers
            KeepAlive = false,
            ProtocolVersion = HttpVersion.Version11, // Default value is HTTP 1.1
            UseDefaultCredentials = false,
            UserAgent = $"DownloaderSample/{Assembly.GetExecutingAssembly().GetName().Version.ToString(3)}"
        }
    };

创建一个下载服务:

var downloader = new DownloadService(downloadOpt);

配置事件处理器(该步骤可以省略):

// Provide `FileName` and `TotalBytesToReceive` at the start of each downloads
    // 在每次下载开始时提供 "文件名 "和 "要接收的总字节数"。
    downloader.DownloadStarted += OnDownloadStarted;

    // Provide any information about chunker downloads, like progress percentage per chunk, speed, total received bytes and received bytes array to live streaming.
    // 提供有关分块下载的信息,如每个分块的进度百分比、速度、收到的总字节数和收到的字节数组,以实现实时流。
    downloader.ChunkDownloadProgressChanged += OnChunkDownloadProgressChanged;

    // Provide any information about download progress, like progress percentage of sum of chunks, total speed, average speed, total received bytes and received bytes array to live streaming.
    // 提供任何关于下载进度的信息,如进度百分比的块数总和、总速度、平均速度、总接收字节数和接收字节数组的实时流。
    downloader.DownloadProgressChanged += OnDownloadProgressChanged;

    // Download completed event that can include occurred errors or cancelled or download completed successfully.
    // 下载完成的事件,可以包括发生错误或被取消或下载成功。
    downloader.DownloadFileCompleted += OnDownloadFileCompleted;

接着就可以下载文件了:

string file = @"D:\1.html";
    string url = @"https://www.coderbusy.com";
    await downloader.DownloadFileTaskAsync(url, file);

下载非 HTTP 协议的文件

除了 WebClient 可以下载 FTP 协议的文件之外,上文所示的其他方法只能下载 HTTP 协议的文件。

aria2 是一个轻量级的多协议和多源命令行下载工具。它支持 HTTP/HTTPS、FTP、SFTP、BitTorrent 和 Metalink。aria2 可以通过内置的 JSON-RPC 和 XML-RPC 接口进行操作。

我们可以调用 aria2 实现文件下载功能。

GitHub 地址:https://github.com/aria2/aria2

下载地址:https://github.com/aria2/aria2/releases

将下载好的 aria2c.exe 复制到应用程序目录,如果是其他系统则可以下载对应的二进制文件。

 public static async Task Download(string url, string fn)
    {
        var exe = "aria2c";
        var dir = Path.GetDirectoryName(fn);
        var name = Path.GetFileName(fn);

        void Output(object sender, DataReceivedEventArgs args)
        {
            if (string.IsNullOrWhiteSpace(args.Data))
            {
                return;
            }
            Console.WriteLine("Aria:{0}", args.Data?.Trim());
        }

        var args = $"-x 8 -s 8 --dir={dir} --out={name} {url}";
        var info = new ProcessStartInfo(exe, args)
        {
            UseShellExecute = false,
            CreateNoWindow = true,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
        };
        if (File.Exists(fn))
        {
            File.Delete(fn);
        }

        Console.WriteLine("启动 aria2c: {0}", args);
        using (var p = new Process { StartInfo = info, EnableRaisingEvents = true })
        {
            if (!p.Start())
            {
                throw new Exception("aria 启动失败");
            }
            p.ErrorDataReceived += Output;
            p.OutputDataReceived += Output;
            p.BeginOutputReadLine();
            p.BeginErrorReadLine();
            await p.WaitForExitAsync();
            p.OutputDataReceived -= Output;
            p.ErrorDataReceived -= Output;
        }

        var fi = new FileInfo(fn);
        if (!fi.Exists || fi.Length == 0)
        {
            throw new FileNotFoundException("文件下载失败", fn);
        }
    }

以上代码通过命令行参数启动了一个新的 aria2c 下载进程,并对下载进度信息输出在了控制台。调用方式如下:

 var url = "https://www.coderbusy.com";
    var save = @"D:\1.html";
    await Download(url, save);

到此这篇关于使用 C# 下载文件的十八般武艺的文章就介绍到这了,更多相关C# 下载文件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C#实现HTTP下载文件的方法

    本文实例讲述了C#实现HTTP下载文件的方法.分享给大家供大家参考. 主要实现代码如下: 复制代码 代码如下: /// <summary> /// Http下载文件 /// </summary> public static string HttpDownloadFile(string url, string path) {     // 设置参数     HttpWebRequest request = WebRequest.Create(url) as HttpWebReques

  • C#开发windows服务实现自动从FTP服务器下载文件

    最近在做一个每天定点从FTP自动下载节目.xml并更新到数据库的功能.首先想到用 FileSystemWatcher来监控下载到某个目录中的文件是否发生改变,如果改变就执行相应的操作,然后用timer来设置隔多长时间来下载.后来又想想,用windwos服务来实现. 效果图: 执行的Log日志: INFO-2016/5/24 0:30:07--日志内容为:0/30/7进行time触发 INFO-2016/5/24 1:30:07--日志内容为:1/30/7进行time触发 INFO-2016/5/

  • C# Winform下载文件并显示进度条的实现代码

    方法一: 效果如下图所示: 代码如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WinShowDown { public partial class F

  • C#下载文件(TransmitFile/WriteFile/流方式)实例介绍

    复制代码 代码如下: 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

  • asp.net C#实现下载文件的六种方法实例

    复制代码 代码如下: protected void Button1_Click(object sender, EventArgs e)  {  /*  微软为Response对象提供了一个新的方法TransmitFile来解决使用Response.BinaryWrite  下载超过400mb的文件时导致Aspnet_wp.exe进程回收而无法成功下载的问题.  代码如下:  */ Response.ContentType = "application/x-zip-compressed"

  • C#中使用HttpDownLoadHelper下载文件实例

    本文实例讲述了C#使用HttpDownLoadHelper下载文件的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.IO; using System.Threading; namespace ProjectWenDangManage.Framework {     /// <sum

  • C#同步、异步远程下载文件实例

    1.使用HttpWebRequest/HttpWebResonse和WebClient 复制代码 代码如下: HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url); WebResponse response = request.GetResponse(); Stream stream = response.GetResponseStream(); if (!response.ContentType.ToLower().St

  • 使用 C# 下载文件的多种方法小结

    目录 简单下载 异步下载 下载文件的同时向服务器发送自定义请求头 如何解决下载文件不完整的问题 使用 Downloader 进行 HTTP 多线程下载 下载非 HTTP 协议的文件 文件下载是一个软件开发中的常见需求.本文从最简单的下载方式开始步步递进,讲述了文件下载过程中的常见问题并给出了解决方案.并展示了如何使用多线程提升 HTTP 的下载速度以及调用 aria2 实现非 HTTP 协议的文件下载. 简单下载 在 .NET 程序中下载文件最简单的方式就是使用 WebClient 的 Down

  • python 下载文件的多种方法汇总

    本文档介绍了 Python 下载文件的各种方式,从下载简单的小文件到用断点续传的方式下载大文件. Requests 使用 Requests 模块的 get 方法从一个 url 上下载文件,在 python 爬虫中经常使用它下载简单的网页内容 import requests # 图片来自bing.com url = 'https://cn.bing.com/th?id=OHR.DerwentIsle_EN-CN8738104578_400x240.jpg' def requests_downloa

  • Javaweb实现上传下载文件的多种方法

    在Javaweb中,上传下载是经常用到的功能,对于文件上传,浏览器在上传的过程中是以流的过程将文件传给服务器,一般都是使用commons-fileupload这个包实现上传功能,因为commons-fileupload依赖于commons-io这个包,所以需要下载这两个包commons-fileupload-1.2.1.jar和commons-io-1.3.2.jar. 1.搭建环境 创建Web项目,将包导入到项目lib下 2.实现文件上传 (第一种上传的方法) 新建upload.jsp页面 <

  • php实现当前页面点击下载文件的简单方法

    php控制器中代码 public function downFile($path = ''){ if(!$path) header("Location: /"); download($path); } download文件下载函数代码 function download($file_url,$new_name=''){ if(!isset($file_url)||trim($file_url)==''){ echo '500'; } if(!file_exists($file_url)

  • Golang 使用http Client下载文件的实现方法

    之前使用beego的http库的时候,有的情况需要下载文件.beego是能实现,但就是有点问题:不支持回调,没法显示下载速度,这在日常开发中是不可忍受的. 看了下beego的实现主要是使用了io.copy函数,于是就深入的看了下实现原理,发现挺简单的,于是就根据io.copy原理实现的一个简单的下载器 //定义要下载的文件 var durl = "https://dl.google.com/go/go1.10.3.darwin-amd64.pkg"; //解析url uri, err

  • linux下上传下载文件夹的方法

    Linux下目录复制:本机->远程服务器 scp -r /home/shaoxiaohu/test1 zhidao@192.168.0.1:/home/test2 test1为源目录,test2为目标目录,zhidao@192.168.0.1为远程服务器的用户名和ip地址. Linux下目录复制:远程服务器->本机 scp -r zhidao@192.168.0.1:/home/test2 /home/shaoxiaohu/test1 zhidao@192.168.0.1为远程服务器的用户名和

  • Python定义一个跨越多行的字符串的多种方法小结

    方法一: >>> str1 = '''Le vent se lève, il faut tenter de vivre. 起风了,唯有努力生存. (纵有疾风起,人生不言弃.)''' >>> str1 'Le vent se lève, il faut tenter de vivre. \n起风了,唯有努力生存.\n(纵有疾风起,人生不言弃.)' 编辑的时候,引号挺对的,但是不知道为什么发布的时候,第一行的引号总是多了一些,其实应该是下面这样的: 不过感觉这种方法不够纯粹

  • Unity延时执行的多种方法小结

    目录 Update计时器 Invoke 协程 DoTween 最开始接触unity的时候,我做延时都是在update里做计时器.后来才发现,我屮艸芔茻,还有这么多种更方便延时执行的方式.现在我们就来捋一捋. 本文列举的有以下四种,如有错漏,欢迎补充指正 ✨ Update Invoke 协程 DoTween 支持参数传入 ✖️ ✖️ ✔️ ✖️ 下表是在不同情况下各方案的执行状态 ✨ Update Invoke 协程 DoTween Time.timeScale = 0 ✔️ ✖️ ✖️ ✔️ a

  • Android实现下载文件功能的方法

    本文所述为Android实现下载文件功能的完整示例代码,对于学习和研究android编程相信会有一定的帮助,尤其是对Android初学者有一定的借鉴价值. 完整功能代码如下: package com.test; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import and

随机推荐