翼度科技»论坛 编程开发 .net 查看内容

C#网络下载器

9

主题

9

帖子

27

积分

新手上路

Rank: 1

积分
27
之前学习了一部分的C#基础,但是感觉会的不多,很多地方依然需要通过做一点小Demo来进行巩固,那么这个C#的网络下载器,就来了
原理讲解

首先我们编写代码之前,我们需要了解下网络下载的原理到底是什么?
学习过C#中IO流部分的知识,或者你有其它的语言的基础,学习过其它语言的文件IO的基础,肯定了解过我们计算机中的数据都是二进制,那么网络中传输的数据本质上也是一样的。


我们在学习文件IO中,都会学习文件的读写操作,读操作(Output),将文件中的二进制数据读出来,写操作(Input)将内存中的二进制数据写入到硬盘中的文件中。


那么网络下载的本质就是文件的读写,其步骤分为以下几步:

  • 向服务器发起请求
  • 服务器接收到请求,返回响应,而这个响应是一个文件流数据
  • 程序接收到响应,读取响应体中的二进制数据(读文件的操作)
  • 将读取的文件二进制数据写入到磁盘中

代码实现

现在已经了解了原理,那么就开始代码实现吧!
  1. namespace WebDownLoad
  2. {
  3.     // 一个下载任务类
  4.     public class DownLoadTask
  5.     {
  6.         public async Task Start(string url,string targetUrl)
  7.         {
  8.             try
  9.             {
  10.                 // 1.先创建一个HttpClient连接
  11.                 // 由于HttpClient实现了IDispose接口,所以我们可以回收它的资源
  12.                 using HttpClient client = new HttpClient();
  13.                 // 1.1.某些网站会反爬,所以我们需要设置一些参数
  14.                 client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61");
  15.                 // 2.进行异步请求
  16.                 HttpResponseMessage  response = await client.GetAsync(url);
  17.                 // 3.请求成功
  18.                 if (response.IsSuccessStatusCode)
  19.                 {
  20.                     // 3.1.读取文件的类型
  21.                     string? type = response.Content.Headers.ContentType?.MediaType;
  22.                     // 3.2.文件的总大小
  23.                     long? totalSize = response.Content.Headers.ContentLength;
  24.                     // 3.3.获取文件流
  25.                     // 缓存区的大小为 10 kb
  26.                     // 当前下载的大小
  27.                     long downloadSize = 0;
  28.                     int length = 0;
  29.                     using BufferedStream bufferedStream = new BufferedStream(
  30.                         await response.Content.ReadAsStreamAsync());
  31.                     // 缓冲区大小 0.5KB
  32.                     byte[] bufferSize = new byte[1024];
  33.                     IEnumerable<byte> targetBuffer = new List<byte>();
  34.                     string suffix = GetType(type);
  35.                     while ((length = bufferedStream.Read(bufferSize, 0, bufferSize.Length)) != 0)
  36.                     {
  37.                         downloadSize += length;
  38.                         long? progress = downloadSize * 100 / totalSize ;
  39.                         targetBuffer = targetBuffer.Concat(bufferSize.ToList());
  40.                         await Console.Out.WriteAsync($"\r下载中{progress}%");
  41.                     }
  42.                     await Console.Out.WriteLineAsync();
  43.                     File.WriteAllBytes(targetUrl + Random.Shared.Next(10, 10000) + suffix, targetBuffer.ToArray());
  44.                 }
  45.                 // 4.请求失败
  46.                 else
  47.                 {
  48.                     Console.WriteLine("请求下载失败");
  49.                 }
  50.             }catch (HttpRequestException e)
  51.             {
  52.                 Console.WriteLine($"请求下载失败:{e.Message}");
  53.             }
  54.         }
  55.         // 检测文件的类型
  56.         private string GetType(string type) {
  57.             string suffix = "";
  58.             if (type.Contains("jpeg"))
  59.             {
  60.                 suffix = ".jpg";
  61.             }
  62.             else if (type.Contains("application/octet-stream"))
  63.             {
  64.                 suffix = ".exe";
  65.             }
  66.             else if (type.Contains("png"))
  67.             {
  68.                 suffix = ".png";
  69.             }
  70.             else if (type.Contains("mp4"))
  71.             {
  72.                 suffix = ".mp4";
  73.             }
  74.             else if (type.Contains("avi"))
  75.             {
  76.                 suffix = ".avi";
  77.             }
  78.             else if (type.Contains("mp3"))
  79.             {
  80.                 suffix = ".mp3";
  81.             }
  82.             else if (type.Contains("mpeg"))
  83.             {
  84.                 suffix = ".m4a";
  85.             }
  86.             return suffix;
  87.         }
  88.     }
  89. }
复制代码
我上面的这段代码,其实有点累赘,大家可以写的更好,不必看我的写法,我对C#的很多类不太熟悉,所以,整体代码的缺点还是很多的。
这里其实为了做出一个正在下载的效果,让控制台用户有体验,做了很多不必要的操作
这里为了使得可以一次性下载多个文件使用异步的操作,来提升程序的下载接收量,其实大家也可以不用异步操作,使用线程来实现
最后实验一下
  1. using WebDownLoad;
  2. namespace WebDownLoad
  3. {
  4.     public class Program
  5.     {
  6.         public async static Task Main(string[] args) {
  7.             while (true)
  8.             {
  9.                 Console.WriteLine("请输入下载地址(如果输入0退出):");
  10.                 string url = Console.ReadLine();
  11.                 if ("0".Equals(url))
  12.                 {
  13.                     break;
  14.                 }
  15.                 DownLoadTask task = new DownLoadTask();
  16.                 task.Start(url, "E:\\网络下载\");
  17.             }
  18.         }
  19.     }
  20. }
复制代码
当前的文件夹中是没有东西的




这里还可以继续下载,同时还有一个问题,我们需要了解,就是在C#中,其实异步并不会新开一个线程,C#底层实现异步其实本质上是使用switch goto 来进状态跳转,也就是它并不会实际上加快处理速度,但是可以加大程序的接收速度,也就是接收很快,但是处理不变,要加快处理还是得开线程,我们线程本身就是带有异步性的,所以这个程序使用线程实现可能是更好的

来源:https://www.cnblogs.com/trueasureyuki/archive/2023/10/24/17785722.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具