Windows程序设计课程作业-3(文件并发下载)

news2024/11/20 20:27:01

目录

目录

1.作业内容

2.作业要求

3.主要思路

 1)窗体和组件初始化

 2)下载管理器实例化

3)按钮点击事件处理

4)窗体加载事件处理

 5)下载消息处理

 4.主要难点

1)多线程管理:

2) UI更新:

3) 错误处理:

4) 资源管理:

5) 用户体验:

5.不足及改进

参考: 

6.代码展示

代码仓库 

7.运行结果
​​​​​


1.作业内容

通过c#实现一个基本的多线程文件下载器,用于从一个文本文件中读取下载链接,并启动多线程下载,可以在Windows窗体应用程序中使用。同时,也可以更新UI显示文件下载内容和进度情况。

  • 并发下载
  • 网络连接
  • ...
下载过程图
下载情况

2.作业要求

请以博客方式提交作业,博客内容需要对代码行进行讲解,阐述设计的主要思路与难点。
请注意,如果想达到博客网站如csdn的优质博文的质量分,需要对博客进行详细描述。
提交方式为提交博客发布地址,并附上本博文的质量分。

3.主要思路

由于核心代码已有,本人只是在此基础上进行修改,理解其核心原理和过程

 1)窗体和组件初始化

  • `Form1()` 构造函数:初始化窗体,并调用 `InitializeComponent()` 方法,后者由WinForms设计器自动生成,用于设置窗体上的控件。
        public Form1()
        {
            InitializeComponent();
        }

 2)下载管理器实例化

  • `DownLoadFile dlf = new DownLoadFile();`:创建 `DownLoadFile` 类的实例,该类负责管理下载任务。
        DownLoadFile dlf = new DownLoadFile();

3)按钮点击事件处理

  • - `btnTest_Click`:当用户点击界面上的某个按钮时触发此事件。
  •   - 读取文本文件 `"下载文件.txt"` 中的每一行,每行包含一个文件名和一个URL,它们通过 `|` 分隔。
  •   - 对每行进行分割,提取文件名和URL。
  •   - 使用 `Uri.EscapeUriString` 对URL进行编码,确保URL在传输过程中的安全性。
  •   - 将文件下载存放路径设置为 `dir` 变量。
  •   - 在列表视图 `listView1` 中为每个下载任务添加一个项,并设置初始状态。
  •   - 调用 `dlf.AddDown` 方法添加下载任务,传入下载链接、存放目录、任务索引和索引的字符串表示。
  •   - 调用 `dlf.StartDown` 开始下载任务。
 private void btnTest_Click(object sender, EventArgs e)
 {
     string[] lines = File.ReadAllLines("D:\\table\\作业\\windows\\作业\\作业三\\DownLoadFile\\下载文件.txt");
     for (int i = 0; i < lines.Length; i++)
     {
         string[] line = lines[i].Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
         if (line.Length == 2)
         {
             string path = Uri.EscapeUriString(line[1]);
             string filename = line[0];
             //string filename = Path.GetFileName(path);
             string dir = @"D:\\table\作业\windows\作业\作业三\DownLoadFile\文件下载存放处";
             ListViewItem item = listView1.Items.Add(new ListViewItem(new string[] { (listView1.Items.Count + 1).ToString(), filename, "0", "0", "0%", "0", "0", DateTime.Now.ToString(), "等待中", line[1] }));
             int id = item.Index;
             dlf.AddDown(path, dir, id, id.ToString());
         }
     }
     dlf.StartDown();
 }

4)窗体加载事件处理

  • - `Form1_Load`:在窗体加载时设置下载器的线程数,并注册下载过程中的消息处理事件 `SendMsgHander`。
        private void Form1_Load(object sender, EventArgs e)
        {
            dlf.ThreadNum = 3;//线程数,不设置默认为3
            dlf.doSendMsg += SendMsgHander;//下载过程处理事件
        }

 5)下载消息处理

  • - `SendMsgHander`:根据下载过程中的不同状态更新UI。
  •   - `DownStatus.Start`:下载开始时更新状态。
  •   - `DownStatus.GetLength`:获取文件长度时更新状态。
  •   - `DownStatus.End` 和 `DownStatus.DownLoad`:下载过程中和下载结束时更新进度、速度和剩余时间。
  •   - `DownStatus.Error`:下载出错时更新错误信息。
 private void SendMsgHander(DownMsg msg)
 {
     switch (msg.Tag)
     {
         case DownStatus.Start:
             this.Invoke((MethodInvoker)delegate ()
             {
                 listView1.Items[msg.Id].SubItems[8].Text = "开始下载";
                 listView1.Items[msg.Id].SubItems[7].Text = DateTime.Now.ToString();
             });
             break;
         case DownStatus.GetLength:
             this.Invoke((MethodInvoker)delegate ()
             {
                 listView1.Items[msg.Id].SubItems[3].Text = msg.LengthInfo;
                 listView1.Items[msg.Id].SubItems[8].Text = "连接成功";
             });
             break;
         case DownStatus.End:
         case DownStatus.DownLoad:
             this.Invoke(new MethodInvoker(() =>
             {
                 this.Invoke((MethodInvoker)delegate ()
                 {
                     listView1.Items[msg.Id].SubItems[2].Text = msg.SizeInfo;
                     listView1.Items[msg.Id].SubItems[4].Text = msg.Progress.ToString() + "%";
                     listView1.Items[msg.Id].SubItems[5].Text = msg.SpeedInfo;
                     listView1.Items[msg.Id].SubItems[6].Text = msg.SurplusInfo;
                     if (msg.Tag == DownStatus.DownLoad)
                     {
                         listView1.Items[msg.Id].SubItems[8].Text = "下载中";
                     }
                     else
                     {
                         listView1.Items[msg.Id].SubItems[8].Text = "下载完成";
                     }
                     Application.DoEvents();
                 });
             }));
             break;
         case DownStatus.Error:
             this.Invoke((MethodInvoker)delegate ()
             {
                 listView1.Items[msg.Id].SubItems[6].Text = "失败";
                 listView1.Items[msg.Id].SubItems[8].Text = msg.ErrMessage;
                 Application.DoEvents();
             });
             break;
     }
 }

 4.主要难点

1)多线程管理:

正确地管理多个下载线程,确保它们不会相互干扰,同时高效地利用系统资源。

2) UI更新:

在多线程环境中安全地更新UI,因为UI控件只能通过创建它们的线程(通常是主线程)进行操作。这里使用了 `Invoke` 方法来确保在主线程上更新UI。

3) 错误处理:

在下载过程中可能会遇到各种错误,如网络问题、文件写入权限问题等。我们需要能够处理这些错误,并给用户适当的反馈。

4) 资源管理:

确保所有资源(如文件流、网络连接)在使用后都能正确关闭和释放,防止资源泄露。

5) 用户体验:

提供清晰的进度指示和错误信息,使用户能够了解下载状态和问题。

5.不足及改进

对下载文件的命名进行优化,下载生成文件具有良好的可阅读性,同时能对其后缀进行自动添加。

能否由用户控制下载哪几个文件,而不是全部下载了。

参考: 

https://www.cnblogs.com/jianzhan/p/7137485.html

6.代码展示

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Gac;

namespace Demo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        DownLoadFile dlf = new DownLoadFile();
        private void btnTest_Click(object sender, EventArgs e)
        {
            string[] lines = File.ReadAllLines("D:\\table\\作业\\windows\\作业\\作业三\\DownLoadFile\\下载文件.txt");
            for (int i = 0; i < lines.Length; i++)
            {
                string[] line = lines[i].Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
                if (line.Length == 2)
                {
                    string path = Uri.EscapeUriString(line[1]);
                    string filename = line[0];
                    //string filename = Path.GetFileName(path);
                    string dir = @"D:\\table\作业\windows\作业\作业三\DownLoadFile\文件下载存放处";
                    ListViewItem item = listView1.Items.Add(new ListViewItem(new string[] { (listView1.Items.Count + 1).ToString(), filename, "0", "0", "0%", "0", "0", DateTime.Now.ToString(), "等待中", line[1] }));
                    int id = item.Index;
                    dlf.AddDown(path, dir, id, id.ToString());
                }
            }
            dlf.StartDown();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            dlf.ThreadNum = 3;//线程数,不设置默认为3
            dlf.doSendMsg += SendMsgHander;//下载过程处理事件
        }
        private void SendMsgHander(DownMsg msg)
        {
            switch (msg.Tag)
            {
                case DownStatus.Start:
                    this.Invoke((MethodInvoker)delegate ()
                    {
                        listView1.Items[msg.Id].SubItems[8].Text = "开始下载";
                        listView1.Items[msg.Id].SubItems[7].Text = DateTime.Now.ToString();
                    });
                    break;
                case DownStatus.GetLength:
                    this.Invoke((MethodInvoker)delegate ()
                    {
                        listView1.Items[msg.Id].SubItems[3].Text = msg.LengthInfo;
                        listView1.Items[msg.Id].SubItems[8].Text = "连接成功";
                    });
                    break;
                case DownStatus.End:
                case DownStatus.DownLoad:
                    this.Invoke(new MethodInvoker(() =>
                    {
                        this.Invoke((MethodInvoker)delegate ()
                        {
                            listView1.Items[msg.Id].SubItems[2].Text = msg.SizeInfo;
                            listView1.Items[msg.Id].SubItems[4].Text = msg.Progress.ToString() + "%";
                            listView1.Items[msg.Id].SubItems[5].Text = msg.SpeedInfo;
                            listView1.Items[msg.Id].SubItems[6].Text = msg.SurplusInfo;
                            if (msg.Tag == DownStatus.DownLoad)
                            {
                                listView1.Items[msg.Id].SubItems[8].Text = "下载中";
                            }
                            else
                            {
                                listView1.Items[msg.Id].SubItems[8].Text = "下载完成";
                            }
                            Application.DoEvents();
                        });
                    }));
                    break;
                case DownStatus.Error:
                    this.Invoke((MethodInvoker)delegate ()
                    {
                        listView1.Items[msg.Id].SubItems[6].Text = "失败";
                        listView1.Items[msg.Id].SubItems[8].Text = msg.ErrMessage;
                        Application.DoEvents();
                    });
                    break;
            }
        }
    }
}

代码仓库 

https://github.com/Tiansky9/sky.git

7.运行结果

下载过程图

下载情况

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1855124.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能优化算法改进策略之局部搜索算子(六)--进化梯度搜索

1、原理介绍 进化梯度搜索(Evolutionary Gradient Search, EGS)[1]是兼顾进化计算与梯度搜索的一种混合算法&#xff0c;具有较强的局部搜索能力。在每次迭代过程中&#xff0c;EGS方法首先用受进化启发的形式估计梯度方向&#xff0c;然后以最陡下降的方式执行实际的迭代步骤&…

【JavaSE ⑧】P219 ~ 225 Date类‘’DateFormat类转化Date和字符串;Calendar类获得日历中某值,修改日历,日历转日期

目录 日期时间类1 Date类概述常用方法 2DateFormat类构造方法格式规则常用方法parse方法format方法 3 Calendar类概念获取方式常用方法get/set方法add方法getTime方法 ● 练习1.判断Date不同参数构造的输出2. 用日期时间相关的API&#xff0c;计算一个人已经出生了多少天。3. 获…

【Java】已解决java.lang.NoSuchMethodException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决java.lang.NoSuchMethodException异常 在Java编程中&#xff0c;java.lang.NoSuchMethodException是一个常见的运行时异常&#xff0c;它通常表示尝试通过反射调用一个不存在…

Ai调教写作技巧,不会还有人在到处找指令吧!一篇文章带你学会生成爆款文章写作指令

大家好&#xff0c;我是网创有方的站长&#xff0c;今天教大家一个重磅级的ai调价指令。 相信很多朋友们都去到处找过写作指令&#xff0c;包括我之前也是&#xff0c;但是随着运用ai写作的次数越来越多&#xff0c;我也是渐渐地熟悉了ai的调教。那么本文的目的是什么呢&#…

使用obdumper对oceanbase进行备份,指定2881端口

1.安装obdumper &#xff08;1&#xff09;下载软件 OceanBase分布式数据库-海量数据 笔笔算数https://www.oceanbase.com/softwarecenter &#xff08;2&#xff09;安装软件 参考&#xff1a;https://www.oceanbase.com/docs/common-oceanbase-dumper-loader-100000000062…

C语言标准库

目录 引言 一、C标准库概述 常用标准库函数 字符串处理 数学运算 动态内存分配 标准库的扩展与限制 扩展功能 使用限制 使用自定义库与第三方库 创建自定义库 使用第三方库 表格总结 标准库头文件及功能 常用标准库函数 总结 引言 C标准库是C编程语言的重要组成…

Android studio登录Google账号超时的解决方法

确保自己已经打开了代理&#xff08;科学上网&#xff09;在设置-外观与行为-系统设置-HTTP代理 中打开“自动检测代理设置”&#xff1a; 再次重新尝试登录Google账号&#xff0c;登陆成功&#xff01; 学术会议征稿 想要了解国内主办的覆盖学科最全最广的学术会议&#xff0c…

redis持久化操作【随记】

持久化 Redis它是将数据保存到内存当中,内存里的数据最大特点: 断电易失.保存在内存的数据就没有了.如果如果这些数据还有用,业务使用啥的,不能就让它这么没有了. redis当中提供持久化机制, 说白了,将内存的数据 —-> 写入到磁盘. –> 持久化. 1 rdb方式 redis database,…

帕金森患者饮食指南:科学调养,呵护健康

&#x1f33c;在医学的广阔领域中&#xff0c;帕金森病作为一种慢性神经系统疾病&#xff0c;除了需要专业的医疗治疗外&#xff0c;日常饮食的调养也显得尤为重要。 今天&#xff0c;就为大家带来一份专为帕金森患者打造的饮食建议&#xff0c;希望能为大家的健康调养提供一些…

泛微E9与金蝶云星空ERP的无缝集成案例详解(包括接口与字段)

业务系统现状 背景介绍 泛微E9和金蝶云星空ERP是两款广泛应用与企业管理的信息系统&#xff0c;分别在移动办公自动化和企业资源计划管理领域占据重要地位。然而企业在使用这些系统时往往面临着信息孤岛和系统孤立的问题&#xff0c;导致数据无法在不系统之间高效流转共享。 当…

微服务——服务治理

目录 1 什么是服务治理&#xff1f;2 为什么需要服务治理&#xff1f;3 服务治理的关键点3.1 服务注册与发现3.2 负载均衡3.3 容错与熔断3.4 服务监控与告警3.5 服务配置管理 4 示例说明5 总结 1 什么是服务治理&#xff1f; 简单来说&#xff0c;服务治理就是对微服务架构中的…

Java:113-Spring Data JPA详解

Spring Data JPA详解 Spring Data Jpa 是应用于Dao层的⼀个框架&#xff0c;简化数据库开发的&#xff0c;作用和Mybatis框架⼀样&#xff0c;但是在使用方式和底层机制是有所不同的&#xff0c;最明显的⼀个特点&#xff0c;Spring Data Jpa 开发Dao的时候&#xff0c;很多场景…

气膜建筑:持久耐用的建筑选择—轻空间

随着科技的发展&#xff0c;气膜建筑以其快速施工、节能环保和灵活多用的特点&#xff0c;正在各个领域获得越来越多的应用。然而&#xff0c;许多人对气膜建筑的耐用程度仍存有疑虑。本文将从气膜建筑的材料、结构设计和维护等方面&#xff0c;深入探讨气膜建筑的耐用性&#…

【Android WebView】WebView基础

一、简介 WebView是一个基于webkit引擎、展现web页面的控件。Android的Webview在低版本和高版本采用了不同的webkit版本内核&#xff0c;4.4后直接使用了Chrome。 二、重要类 以WebView类为基础&#xff0c;WebSettings、WebViewClient、WebChromeClient为辅助共同完成安卓段加…

阿里云,大周末彻底要爆!

大家好&#xff0c;我是肉哥&#xff0c;熟悉我的人都知道&#xff0c;每年6.18我都会带领大家薅阿里云的羊毛&#xff0c;今年也不例外&#xff0c;作为程序员搞台ECS&#xff0c;做个项目满满的成就感&#xff01;阿里内部小伙伴透漏&#xff0c;今年的618活动优惠力度更是拉…

FlinkCDC pipeline模式 mysql-to-paimon.yaml

flinkcdc 需要引入&#xff1a; source端&#xff1a; flink-cdc-pipeline-connector-mysql-xxx.jar、mysql-connector-java-xxx.jar、 sink端&#xff1a; flink-cdc-pipeline-connector-paimon-xxx.jar flinkcdc官方提供connect包下载地址&#xff0c;pipeline模式提交作业和…

成章数据库安装体验

对标Redis的国产数据库 一位来自国产数据库的朋友想请我试用一下他们的产品。并且直言早期问题比较多&#xff0c;还请多多包涵。一般对于这种比较客观和友好的我都愿意试试。对于怼天怼地吊打谁的我个人就不尝试了。 他们中文名字叫“成章数据库“我就尝试从一个不了解产品的…

Qt底层原理:深入解析QWidget的绘制技术细节(1)

在Qt5中&#xff0c;QWidget的绘制流程比较分散&#xff0c;网上介绍的文章也很少&#xff0c;因此写一篇文章总结记录一下这部分的知识点。 笔者使用的是Qt5.15.2的源码。 基本的绘制流程&#xff1a;从update到合成 更新请求&#xff08;Invalidate&#xff09;: 当一个QWidg…

线程间通信方式(互斥(互斥锁)与同步(无名信号量、条件变量))

1通信机制&#xff1a;互斥与同步 线程的互斥通过线程的互斥锁完成&#xff1b; 线程的同步通过无名信号量或者条件变量完成。 2 互斥 2.1 何为互斥&#xff1f; 互斥是在多个线程在访问同一个全局变量的时候&#xff0c;先让这个线程争抢锁的资源&#xff0c;那个线程争抢…

理解广角镜头的视野和畸变

为什么广角镜头的视野会比长焦镜头的视野大呢&#xff1f; 我之前用等光程解释了景深&#xff0c;也解释了为什么焦距越远&#xff0c;成像越大&#xff0c;但是从来没有提到过视野范围这个概念。实际上在我之前建立的数学模型中&#xff0c;物曲面S是无限大的&#xff0c;像曲…