http文件批量多线程下载之winform

这里简单的介绍一种从http获取文件然后下载到本地的方法,开始我用单线程下载,文件多的情况下速度太慢了,后来就采用多线程,这里琢磨了好久才整出来一个。这里的部分代码是在博客园找到的,具体是在哪里不是很清楚了,搜索关键词大概是http下载文件,感谢下。

1.关于多线程的思路,文件下载线程,日志记录线程(使用txt记录下载文件日志),UI线程。每个线程独立运行,互不干扰。

(1)这里说明下为什么要给UI单独一个线程,主要是因为文件数量太多的时候,如果这个线程是和文件下载线程和在一起的时候,我稍微一动下winform的界面,程序就会卡死,直到程序结束,我表示我已经注销了好多次电脑了。大哭

(2)关于日志记录线程,因为文件下载是多线程,我这里就不能把日志记录在文件下载线程里面,不然几个线程一起占用txt的文件读写。这里会打架的。

(3)关于文件下载线程,这里比较简单了,我启用了十个线程做文件下载,每个文件下载单独的使用一个线程,线程完了之后继续下一个任务进行下载。这里我测试了下,十个线程下载速度还是比较理想的,内存使用也不是很大,但是这样可能很占用服务器IO内存,还是要稍微注意点的,线程不要太多了,影响网站的访问就不是很好了。

不说了 贴代码


private bool flag = true;//进程标识符 
        private int n = 0;//进程记录数量
        private List<string> list=new List<string>(); //日志记录临时表

//初始化代码
public HttpDownloadFile()
        {
            InitializeComponent();
            HttpDownloadFile.CheckForIllegalCrossThreadCalls = false;//这里必须设置,忘记是做啥用的,大家用的时候可以先不设置,看是报什么错误先
        }
点击按钮进行文件下载
private void button1_Click(object sender, EventArgs e)
        {
            Thread th = new Thread(main);
            th.Start();//启动文件下载主线程
            Thread thtxt = new Thread(writeTxt);
            thtxt.Start();//启动日志记录线程
            
        }

日志线程函数说明:

protected void writeTxt() {
            while (true)
            {
                List<string> templist = new List<string>(list);//将list复制到templist
                foreach (string msg in templist)
                {
                    string transferFile = textBox3.Text.Trim();
                    DateTime dt = DateTime.Now;
                    string str;
                    str = msg;
                    StreamWriter sw = new StreamWriter(transferFile + dt.Year + "" + dt.Month + "" + dt.Day + "log.txt", true);
                    sw.WriteLine(dt.ToString() + ":" + str);
                    sw.Close();//写入 
                    list.Remove(msg);
                }
                templist = new List<string>();
            }
        }

文件下载主线程:

private void main() {
            DateTime dt = DateTime.Now;//开始接收时间   
            label5.Text = dt.ToString();
            List<string> list = new List<string>();
            DataSet ds = new DataSet();
            //从数据库获取文件路径
            if (checkBox1.Checked)
            {
                ds = Dal.DalDatebase.getUrl(textBox2.Text.Trim());
            }
            else {
                ds = Dal.DalDatebase.getUrl(textBox2.Text.Trim(),1);
            }
            DataRowCollection drc = ds.Tables[0].Rows;
            textBox4.Text = drc.Count.ToString();
            int i = 0;            
            string transferFile = textBox3.Text.Trim();
            while (flag)
            {
                if (i == drc.Count) {
                    flag = false;
                }
                if (n < 10)
                {
                    string tempurl = drc[i]["url"].ToString();
                    string fileName = tempurl.Split('/')[tempurl.Split('/').Length - 1];
                    ParameterizedThreadStart hbStart = new ParameterizedThreadStart(GetFile);
                    Thread hbth = new Thread(hbStart);
                    conData con = new conData();
                    con.fileName = fileName;
                    con.i = i;
                    con.transferFile = transferFile;
                    con.url = tempurl;
                    object ur = con;
                    hbth.Start(ur);
                    n++;//线程数
                    i++;//数据库获取的数据增量
                }
                
            }
            if (n == 0)//线程结束之后弹出文件接收完毕
            {
                MessageBox.Show("文件接收完毕");
                dt = DateTime.Now;//开始接收时间   
                label5.Text = dt.ToString();
            }
        }

下载文件代码:
private void GetFile(object str)
        {
            conData con = (conData)str;
            try
            {                            
                listBox1.Items.Add("文件(" + con.i + "):" + con.fileName + "开始接收");
                FileStream fs = new FileStream(con.transferFile + con.fileName, System.IO.FileMode.Create);
                try
                {
                    HttpWebRequest request= (HttpWebRequest)HttpWebRequest.Create(con.url);
                    long filesize = request.GetResponse().ContentLength;//取得目标文件的长度   
                    if (filesize > 0)
                    {
                        byte[] nbytes = new byte[512];
                        System.IO.Stream ns = request.GetResponse().GetResponseStream();//获得接收流   
                        int nreadsize = ns.Read(nbytes, 0, 512);
                        while (nreadsize > 0)
                        {
                            fs.Write(nbytes, 0, nreadsize);
                            nreadsize = ns.Read(nbytes, 0, 512);
                        }
                        fs.Close();
                        ns.Close();
                    }
                    request.Abort();
                }
                catch (Exception er)
                {
                    listBox1.Items.Add("文件(" + con.i + "):" + con.fileName + "接收失败,错误信息:"+er.Message);
                    fs.Close();
                }
                listBox1.Items.Add("文件(" + con.i + "):" + con.fileName + "接收完毕!");
                listBox1.SelectedIndex = listBox1.Items.Count - 1;
                list.Add("文件(" + con.i + "):" + con.fileName + "接收完毕!");
            }
            catch (Exception e)
            {
                list.Add("文件(" + con.i + "):" + con.fileName + "接收失败!错误信息:" + e.Message);
            }
            n--;
        }
多线程传参的时候是对象形式,我把多个对象写成了一个class,方便传参

public class conData {
        public string transferFile { set; get; }
        public string url { set; get; }
        public string fileName { set; get; }
        public int i { set; get; }
    }

private void button2_Click(object sender, EventArgs e)
        {
            flag = false;//原有的线程继续运行,不会增加新的进程  
            this.Close();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            Dispose();
            System.Environment.Exit(0);  //结束所有线程
            this.Close();
        }
好了 也在这里代码也基本结束了。如果大家有什么疑问或者有什么改进的意见,欢迎留言。做就要做的更好。





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值