承云简易下载器,批量下载漫画等连续文件,用WebClient实现异步下载

六月 16, 2013 实用玩意, 技术 @海德

MyDownload承云简易下载器,站长自己也一直使用(站长=技术+宅+闲得发慌);本文除了提供这个工具,主要是想分享一些设计思路和源代码

飞网简易批量下载器

如上界面是从猪猪字幕组上下载火影忍者的示例,而软件本身具备如下特性:

1、能支持两个通配符批量下载系列漫画、压缩分包等名称连续且有规则文件;
2、支持使用代理下载,自动获取IE代理,是企业内网用户的福音;
3、支持设定引用URL,从而兼容某些站点针对盗链的来源过滤;
4、添加了防并发延时功能用来兼容某些站点对并发连接数的限制;
5、下载后会自动保存本次界面设置,下次打开程序将自动恢复现场;
6、采用异步下载方案,随时反馈工作状态、响应用户操作。

下载安装包 ◥
(绿色软件,解压即用)

 

最后分享核心代码片段,非技术宅可止步 ^_^

WebClient 异步下载,兼容代理服务器上网

        /// <summary>
        /// 使用异步方法下载
        /// </summary>
        /// <param name="url"></param>
        /// <param name="directory"></param>
        private void Download(string url, string directory)
        {
            WebClient client = new WebClient();
            Uri uri = new Uri(url);

            //请求
            try
            {
                WebRequest request = WebRequest.Create(uri);
            }
            catch
            {
            }

            //目录
            if (!System.IO.Directory.Exists(directory))
            {
                System.IO.Directory.CreateDirectory(directory);
            }
            //文件名
            string fileName = url.Substring(url.LastIndexOf('/') + 1, url.Length - url.LastIndexOf('/') - 1);
            if (fileName.Contains("?"))
            {
                fileName = fileName.Substring(0, fileName.LastIndexOf("?"));
            }
            string fullFileName = directory + "\\" + fileName;
            while (System.IO.File.Exists(fullFileName)) //重名
            {
                fullFileName = string.Format("({0}){1}",
                    DateTime.Now.ToString("HHmmssfff"),
                    fullFileName
                    );
            }

            if (proxyFlag.Checked) //指明需要代理
            {
                try
                {
                    WebProxy webProxy = new WebProxy();
                    Uri webProxyAddress = new Uri(proxy.Text);
                    webProxy.Address = webProxyAddress;
                    webProxy.UseDefaultCredentials = true;
                    client.Proxy = webProxy;
                }
                catch (Exception error)
                {
                    MessageBox.Show("应用代理失败!\n程序将继续执行……\n\n原因:" + error.Message, "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }

            //引用Url
            client.Headers.Add("Referer:" + referer.Text);

            client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
            client.OpenReadAsync(uri, url + "|" + fullFileName); //把源地址和目标地址作为参数传送
        }

        /// <summary>
        /// 异步下载回调
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            string url = (e.UserState.ToString().Split('|'))[0].Trim();
            string fileName = (e.UserState.ToString().Split('|'))[1].Trim();
            BufferedStream fileStream;

            try
            {
                //获取下载流,new一个出来
                fileStream = new BufferedStream(e.Result);
            }
            catch (Exception error)
            {
                this.ShowMessage("Fail: " + url + " -> " + fileName + " Error: " + error.Message);
                return;
            }

            try
            {
                //保存文件
                this.SaveFile(fileStream, fileName);
            }
            catch (Exception error)
            {
                this.ShowMessage("Fail: " + url + " -> " + fileName + " Error: " + error.Message);
                return;
            }

            //成功
            this.ShowMessage("Download: " + url + " -> " + fileName);
        }

容易让人迷茫的如何获取IE默认代理,其实只需要一句话

proxy.Text = WebProxy.GetDefaultProxy().Address.ToString();

最后,借助缓冲块把文件流写入文件中,非常大众化的方法

        /// <summary>
        /// 把文件流写入文件中
        /// </summary>
        /// <param name="fileStream"></param>
        /// <param name="filaName"></param>
        private void SaveFile(Stream fileStream, string fileName)
        {
            using (FileStream newFile = new FileStream(fileName, FileMode.Create, FileAccess.Write))
            {
                //缓冲区
                int bufferSize = 1024;
                byte[] buffer = new byte[bufferSize];

                //判断流是否能读
                if (!fileStream.CanRead)
                {
                    throw new Exception("FileStream can not be read !");
                }

                //先读一次
                int readLength = fileStream.Read(buffer, 0, bufferSize);

                while (readLength > 0) //若能够读到内容
                {
                    newFile.Write(buffer, 0, readLength);

                    //尝试读下一次
                    readLength = fileStream.Read(buffer, 0, bufferSize);
                }

                newFile.Flush();
            }
        }