• C#net多线程多文件压缩下载


    先上效果图,大家看看

    总体效果如上所示,至于为什么会有两个按钮,是因为一个是html的按钮,一个是服务器按钮,服务器按钮是用来触发压缩包的下载,该按钮可以自行通过样式隐藏掉。

    功能效果说明:项目中涉及到从其它服务器上面下载文件,然后在推送给本机用户,一个文件的话,直接推送就好,涉及到多个文件时,则需要先打包压缩好,再一次推送到客户端。整个流程:获取文件到程序发布所在服务器------>将所有文件进行打包压缩----->推送到本机

    之前我做的样子是直接在程序后台完成,没有使用多线程,所以导致多文件、大文件的时候,整个程序就卡死,导致用户不能干其它的任何操作,于是在用户的强烈要求下,我就跟随项目经理研究研究多线程来搞定这个问题。(别笑,以前没用过多线程,不明白)

    我先说说如上图所示的整个代码流程,随后会给所有代码贴上

    1.引用ajax、压缩的dll。

    (AjaxPro.dll    ------   http://download.csdn.net/detail/loushuibazi/8024221)

    (ICSharpCode.SharpZipLib.dll    ------   http://download.csdn.net/detail/loushuibazi/8024261)

    其中AjaxPro的使用方法,各位就百度搜索一下,很多文章都有介绍,使用其它也很方便。

    2.编辑好页面的进度显示功能,一个div嵌套一个div,内部的div高度100%,宽度也按照百分比来调,设置一下颜色,就是进度条的样子了,而进度条的数据,则在js中通过定时读取进度来调整。另外页面在设置一个显示文本的地方即可。

    3.后台就只有三四个方法,各干各的事情,先说说 CreateUserFolderInfo(string uid)

    通过方法传来用户的ID,以该ID为准,创建用户一系列所需要用的东西:用户文件存放的文件夹的名称、ini配置文件、用户需要压缩的文件夹的名称、zip文件保存的路径、zip文件的名称。创建好以上文件或文件夹后(压缩文件在此步骤无需创建,在压缩的过程中,里面涉及到创建),将涉及到的路径都打包装箱。

    这里说明一下ini配置文件:针对用户的每一次下载,创建一个对应的配置文件,该配置文件保存相关的进度信息,给前台用来读取,让用户知道实时的进度情况。

    注:涉及到一些参数的传输,若此处能创建好的,最好全部创建好,并装箱一块传递,那么此方法就可以用来当作控制方法了。

    4.前台调用的方法:GetImageData(string uid)

    该方法主要就是调用CreateUserFolderInfo方法,之后查询数据,然后将数据装箱到参数中,作为一个整体的参数,传参到多线程当中。然后启动线程,最后并把该参数仍到前台去,因为前台也涉及到使用相关参数,这样就无需再来后台获取了。

    5.多线程执行的方法 ThreadMethod(Object o)

    将装箱的参数全部拆箱,将文件都下载到本地,压缩文件夹,关闭线程。

    6.ReadProgress 方法:前台定时调用,读取ini文件中的进度信息

    7.btn_DownloadFile_Click :服务器按钮的单击使用,用来推送压缩文件,并删除用户文件夹。至于压缩包,则做定期删除。

    以下为涉及到的代码。

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test_DownloadImage.aspx.cs"
        Inherits="ChildrenPageFolder_Test_DownloadImage" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>图片下载</title>
        <script language="javascript" type="text/javascript">
    
            var userFileInfo = null;
            function DownImg() {
                userFileInfo = ChildrenPageFolder_Test_DownloadImage.GetImageData("admin").value;
                for (var i = 0; i < userFileInfo.keys.length; i++) {
                    if (userFileInfo.keys[i] == "用户下载ini配置文件路径") {
                        userIniPath = userFileInfo.values[i];
                    }
                    if (userFileInfo.keys[i] == "ini文件内标识项") {
                        userIniOps = userFileInfo.values[i];
                    }
                    if (userFileInfo.keys[i] == "ini文件内标识符") {
                        userIniIden = userFileInfo.values[i];
                    }
                    if (userFileInfo.keys[i] == "用户文件夹目录") {
                        userFolderUrl = userFileInfo.values[i];
                    }
                }
                setTimeout(DealPro, 500);
            }
    
            var js_readProTime = null;
            var userIniPath = null; var userIniOps = null; var userIniIden = null;
            var userFolderUrl = "";
            function DealPro() {
                // 显示图片下载进度
                var proVal = ChildrenPageFolder_Test_DownloadImage.ReadProgress(userIniPath, userIniOps, userIniIden).value;
                document.getElementById("span_proNum").innerHTML = proVal.values[1] + "" + proVal.values[2] + "/" + proVal.values[0];
                document.getElementById("pbar").style.width = ((proVal.values[2] / proVal.values[0]) * 100) + "%";
                if (proVal.values[3] != "true") {
                    setTimeout(DealPro, 500);
                } else {
                    document.getElementById("pbar").style.width = "100%";
                    document.getElementById("hd_downFileUrl").value = proVal.values[4];
                    document.getElementById("hd_userFolderUrl").value = userFolderUrl;
                    document.getElementById("btn_DownloadFile").click();
                    document.getElementById("span_proNum").innerHTML = "数据下载,处理完成!";
    
                }
            }
    
    
        </script>
    </head>
    <body style="margin:0px; padding:0px;">
        <form id="form1" runat="server">
        <div>
            <input type="button" value="图片下载" onclick="DownImg()" />
            <asp:Button ID="btn_DownloadFile" runat="server" Text="下载按钮(服务器按钮)" OnClick="btn_DownloadFile_Click" />
            <input id="hd_downFileUrl" type="hidden" runat="server" value="" />
            <input id="hd_userFolderUrl" type="hidden" runat="server" value="" />
        </div>
        <div style="border: gray 1px solid;  200px; height: 20px;">
            <div id="pbar" style="height: 100%; background-color: #00ff00;  0%;">
            </div>
        </div>
        <span id="span_proNum" style="font-size: 13px;"></span>
        </form>
    </body>
    </html>
    页面前台代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Data;
    using System.IO;
    using System.Threading;
    using System.Text;
    using System.Net;
    using System.Runtime.InteropServices;
    
    public partial class ChildrenPageFolder_Test_DownloadImage : System.Web.UI.Page
    {
    
        // 下载图片、压缩图片线程
        public Thread threadDownloadFile;
    
        protected void Page_Load(object sender, EventArgs e)
        {
            AjaxPro.Utility.RegisterTypeForAjax(typeof(ChildrenPageFolder_Test_DownloadImage));
        }
    
    
    
        /// <summary>
        /// 根据用户ID,创建此次下载,用户需要涉及到的文件信息
        /// </summary>
        /// <param name="uid"> 用户ID </param>
        /// <returns></returns>
        public Dictionary<string, Object> CreateUserFolderInfo(string uid)
        {
    
            // 设置好用户下载文件所需用户到的目录、文件名称
    
            string yhxxml = Server.MapPath("~/DownloadFile/");                              // 用户信息目录
            string yhwjxmc = uid + "_" + Guid.NewGuid().ToString();                         // 用户文件夹名称
            string yhml = yhxxml + yhwjxmc + @"";                                          // 用户文件夹目录(用户信息目录 + 用户文件夹名称)
    
            string xzwjjmc = "Files";                                                       // 需要下载的文件夹名称(存放位置-未压缩)
            string xzwjjml = yhml + xzwjjmc + @"";                                         // 需要下载的文件夹目录(存放位置-未压缩)
    
            string yhiniwjmc = uid + ".ini";                                                // 用户ini文件名称
            string iniwjlj = yhml + yhiniwjmc;                                              // 用户ini文件路径
    
            string xzwjcfml = Server.MapPath("~/KKfile/");                                  // zip下载文件存放目录(压缩包)
            Random rd = new Random();
            string xzwjmc = uid + "_" + "DownloadFile_" + rd.Next(1000, 9999) + ".Zip";     // zip下载文件名称
            string zipxzlj = xzwjcfml + xzwjmc;                                             // zip文件下载路径
    
    
            // 创建相关文件夹、ini配置文件
            if (!Directory.Exists(xzwjcfml)) { Directory.CreateDirectory(xzwjcfml); }
            Directory.CreateDirectory(xzwjjml);
    
            Dictionary<string, Object> iniParams = new Dictionary<string, object>();
            iniParams.Add("DataCount", "DataCount");
            iniParams.Add("Steps", "Steps");
            iniParams.Add("Progress", "Progress");
            iniParams.Add("IsEnd", "IsEnd");
            iniParams.Add("DownFileUrl", "");
    
            string ident = "Text";
            using (FileStream fs = File.Create(iniwjlj))
            {
                StreamWriter sw = new StreamWriter(fs, Encoding.GetEncoding("gb2312"));
                sw.WriteLine("[" + iniParams["DataCount"] as string + "]");
                sw.WriteLine(ident + "=0");
                sw.WriteLine("[" + iniParams["Steps"] as string + "]");
                sw.WriteLine(ident + "=等待查询结果返回");
                sw.WriteLine("[" + iniParams["Progress"] as string + "]");
                sw.WriteLine(ident + "=0");
                sw.WriteLine("[" + iniParams["IsEnd"] as string + "]");
                sw.WriteLine(ident + "=false");
                sw.WriteLine("[" + iniParams["DownFileUrl"] as string + "]");
                sw.WriteLine(ident + "=0");
                sw.Close();
            }
    
            // 整理反馈给前端的信息
            Dictionary<string, Object> userParams = new Dictionary<string, Object>();
            userParams.Add("用户ID", uid);
            userParams.Add("用户文件夹目录", yhml);
            userParams.Add("用户文件存放目录名称", xzwjjmc);
            userParams.Add("用户文件存放目录", xzwjjml);
            userParams.Add("用户下载ini配置文件路径", iniwjlj);
            userParams.Add("ini文件内标识项", iniParams);
            userParams.Add("ini文件内标识符", ident);
            userParams.Add("zip文件存放目录", xzwjcfml);
            userParams.Add("zip文件名称", xzwjmc);
            userParams.Add("zip文件下载路径", zipxzlj);
            return userParams;
        }
    
    
    
        /// <summary>
        /// 下载图片数据
        /// </summary>
        /// <param name="uFileName"> 用户目录 </param>
        [AjaxPro.AjaxMethod]
        public Dictionary<string, Object> GetImageData(string uid)
        {
            Dictionary<string, Object> userInfo = CreateUserFolderInfo(uid);
    
            // 获取出卡口图片列表
            KaKouBLL kkb = new KaKouBLL();
            DataTable dt = kkb.GetXmlSqlByParams(0, 10, false, "<colName>TGSJ</colName><op>></op><colValue>to_date('2014-09-25 00:00:00','yyyy-MM-dd hh24:mi:ss')</colValue><join>and</join><colName>TGSJ</colName><op><</op><colValue>to_date('2014-09-25 23:59:59','yyyy-MM-dd hh24:mi:ss')</colValue>", "CROSS");
            userInfo.Add("exportData", dt);
            IniFileControl.WriteString("DataCount", "Text", dt.Rows.Count.ToString(), userInfo["用户下载ini配置文件路径"] as string);
            
            // 启动图片下载线程
            ParameterizedThreadStart pts = new ParameterizedThreadStart(ThreadMethod);
            threadDownloadFile = new Thread(pts);
            Object o = userInfo;
            threadDownloadFile.Start(o);
    
            return userInfo;
        }
    
    
        /// <summary>
        /// 线程启动需要执行的任务
        /// </summary>
        /// <param name="o"></param>
        public void ThreadMethod(Object o)
        {
            try
            {
                Dictionary<string, Object> userParams = o as Dictionary<string, Object>;
                DataTable dt = userParams["exportData"] as DataTable;
                string userImageFolderPath = userParams["用户文件存放目录"] as string;
                string userIniPath = userParams["用户下载ini配置文件路径"] as string;
                string userFolderPath = userParams["用户文件夹目录"] as string;
                string[] zipInfo = { userParams["zip文件存放目录"] as string, userParams["zip文件名称"] as string };
    
    
                // 下载图片到服务器
                IniFileControl.WriteString("Steps", "Text", "从卡口服务器获取图片", userIniPath);
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    string imgName = (i + 1) + "_" + dt.Rows[i]["车辆号牌"].ToString() + ".jpg";
                    string imgUrl = dt.Rows[i]["照片1"].ToString();
                    Download(imgUrl, userImageFolderPath + "/" + imgName);
    
                    IniFileControl.WriteString("Progress", "Text", (i + 1).ToString(), userIniPath);
                }
    
                // 压缩图片
                IniFileControl.WriteString("Steps", "Text", "开始压缩图片", userIniPath);
                IniFileControl.WriteString("Progress", "Text", "0", userIniPath);
    
                //实例化一个ZipManager类,用于压缩
                ZipManager zm = new ZipManager();
                zm.SetIniParams(userIniPath, "Progress", "Text");   // 设置操作ini文件的相关参数
    
                string zipFolderName = "Files";
                zm.ZipFile(userFolderPath, zipFolderName, userParams["zip文件存放目录"] as string, userParams["zip文件名称"] as string);
    
                // 设置下载压缩包的路径
                string zipFile = (userParams["zip文件存放目录"] as string) + (userParams["zip文件名称"] as string);
                IniFileControl.WriteString("DownFileUrl", "Text", zipFile, userIniPath);
    
                IniFileControl.WriteString("Steps", "Text", "完成压缩,推送到本机", userIniPath);
                IniFileControl.WriteString("Progress", "Text", "0", userIniPath);
                IniFileControl.WriteString("IsEnd", "Text", "true", userIniPath);
    
                // 关闭线程
                threadDownloadFile.Abort();
    
            }
            catch (Exception)
            {
                // 关闭线程
                threadDownloadFile.Abort();
                throw;
            }
    
        }
    
        /// <summary>
        /// 将图片下载到指定位置
        /// </summary>
        /// <param name="imgpath">图片的URL</param>
        /// <param name="filepath">本地磁盘位置及文件名</param>
        public void Download(string imgpath, string filepath)
        {
            try
            {
                WebRequest request = WebRequest.Create(imgpath);
                using (WebResponse response = request.GetResponse())
                {
                    using (Stream reader = response.GetResponseStream())
                    {
                        using (FileStream writer = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write))
                        {
                            byte[] buff = new byte[512];
                            int c = 0;
                            while ((c = reader.Read(buff, 0, buff.Length)) > 0)
                            {
                                writer.Write(buff, 0, c);
                            }
                        }
                    }
                }
    
            }
            catch (Exception ex)
            {
                string aaa = ex.Message;
            }
        }
    
    
        /// <summary>
        /// 读取ini配置文件的进度信息
        /// </summary>
        /// <param name="url">ini文件路径</param>
        /// <param name="ops">标识项</param>
        /// <param name="Iden">标识符</param>
        /// <returns>查询结果</returns>
        [AjaxPro.AjaxMethod]
        public Dictionary<string, Object> ReadProgress(string url, Dictionary<string, Object> ops, string Iden)
        {
            Dictionary<string, Object> returnDic = new Dictionary<string, object>();
            foreach (string item in ops.Keys)
            {
                returnDic.Add(item, IniFileControl.ReadString(item, Iden, url));
            }
            return returnDic;
        }
    
    
        /// <summary>
        /// 服务器按钮下载事件。用来下载压缩文件
        /// </summary>
        protected void btn_DownloadFile_Click(object sender, EventArgs e)
        {
            // 删除用户文件夹
            System.IO.Directory.Delete(this.hd_userFolderUrl.Value, true);
    
            // 下载压缩包
            string filePath = this.hd_downFileUrl.Value;
            FileInfo file = new FileInfo(filePath);
            Response.Clear();
            Response.Charset = "GB2312";
            Response.ContentEncoding = Encoding.Default;
            Response.AddHeader("Content-Disposition", "attachment;filename=" + file.Name);
            Response.AddHeader("Content-Length", file.Length.ToString());
            Response.WriteFile(file.FullName);
            Response.End();
    
    
        }
    }
    页面后台代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using ICSharpCode.SharpZipLib.Zip;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    
    /// <summary>
    ///ZipManager 的摘要说明
    /// </summary>
    public class ZipManager
    {
    
        private int _currentNum = 0;
        public int currentNum
        {
            get
            {
                return _currentNum;
            }
        }
    
    
        public string iniFile_path = string.Empty;          // ini文件路径
        public string iniFile_proName = string.Empty;       // ini文件节点属性
        public string iniFile_colName = string.Empty;       // ini文件节点属性的名称
        private bool iniFile_isWriteIniFile = false;        // ini文件检测
        /// <summary>
        /// 操作ini配置文件参数
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="pro">标识项</param>
        /// <param name="col">标识符</param>
        public void SetIniParams(string path, string pro, string col)
        {
            // 若传入的值有空值,则无效
            if (!string.IsNullOrEmpty(path) || !string.IsNullOrEmpty(pro) || !string.IsNullOrEmpty(col))
            {
                this.iniFile_path = path;
                this.iniFile_proName = pro;
                this.iniFile_colName = col;
                this.iniFile_isWriteIniFile = true;
            }
        }
    
    
        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="zipFolderDir"></param>
        /// <param name="zipfile"></param>
        public void ZipFile(string zipFolderDir, string zipFolderDir_Name, string zipDir, string zipName)
        {
            string zipFilePath = zipDir + zipName;
            ZipOutputStream u = new ZipOutputStream(File.Create(zipFilePath));
            //向压缩文件流加入内容
            this.AddZipEntry(zipFolderDir, zipFolderDir_Name, u, out u);
            // 结束压缩
            u.Finish();
            u.Close();
        }
    
    
        /// <summary>
        /// 将文件转换为流压缩进压缩文件
        /// </summary>
        /// <param name="pDir">需要压缩的路径</param>
        /// <param name="pName">需要压缩的文件夹名称</param>
        /// <param name="u">现有的源ZipOutputStream</param>
        /// <param name="j">out j为已添加“ZipEntry”的“ZipOutputStream”</param>
        public void AddZipEntry(string pDir, string pName, ZipOutputStream u, out ZipOutputStream j)
        {
            string filePath = pDir + pName;
            if (Directory.Exists(filePath)) //文件夹的处理  
            {
                DirectoryInfo di = new DirectoryInfo(filePath);
                FileInfo[] fs = di.GetFiles();
    
                for (int i = 0; i < fs.Length; i++)
                {
                    string fName = fs[i].FullName;
    
                    if (File.Exists(fName)) //文件的处理  
                    {
                        u.SetLevel(9);      //压缩等级  
                        FileStream f = File.OpenRead(fName);
                        byte[] b = new byte[f.Length];
                        f.Read(b, 0, b.Length);          //将文件流加入缓冲字节中  
                        ZipEntry z = new ZipEntry(fName.Replace(pDir, ""));
                        u.PutNextEntry(z);             //为压缩文件流提供一个容器  
                        u.Write(b, 0, b.Length); //写入字节  
                        f.Close();
                        _currentNum++;//增加一个数量
                        IniFileControl.WriteString(this.iniFile_proName, this.iniFile_colName, _currentNum.ToString(), this.iniFile_path);
                    }
                }
    
            }
    
            j = u;    //返回已添加数据的“ZipOutputStream”  
        }
    
    
        /// <summary>
        /// 若路径为【D:	emp】,则在最后增加""【D:	emp】
        /// </summary>
        /// <param name="oldDir"></param>
        /// <returns></returns>
        private string UpdateDir(string oldDir)
        {
            if (oldDir.LastIndexOf(@"/") != oldDir.Length - 1)
            {
                oldDir += @"";
            }
            return oldDir;
        }
    
    }
    压缩类的代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Runtime.InteropServices;
    using System.Text;
    
    /// <summary>
    ///IniFileControl 的摘要说明
    /// </summary>
    public class IniFileControl
    {
        public IniFileControl()
        {
            //
            //TODO: 在此处添加构造函数逻辑
            //
        }
    
    
        // 声明读写INI文件的API函数
        [DllImport("kernel32")]
        private static extern bool WritePrivateProfileString(string section, string key, string val, string filePath);
        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
    
        /// <summary>
        /// 写INI文件
        /// </summary>
        /// <param name="section"> 标识项 </param>
        /// <param name="ident"> 标识符 </param>
        /// <param name="value"></param>
        /// <param name="filePath"> ini文件路径 </param>
        public static void WriteString(string section, string ident, string value, string filePath)
        {
            if (!WritePrivateProfileString(section, ident, value, filePath))
            {
                throw (new ApplicationException("写Ini文件出错"));
            }
        }
    
        /// <summary>
        /// 读取INI文件指定
        /// </summary>
        /// <param name="section"> 标识项 </param>
        /// <param name="ident"> 标识符 </param>
        /// <param name="filePath"> ini文件路径 </param>
        /// <returns></returns>
        public static string ReadString(string section, string ident, string filePath)
        {
            StringBuilder s = new StringBuilder(500);
            GetPrivateProfileString(section, ident, "", s, 500, filePath);
            return s.ToString().Trim();
        }
    
    
    }
    ini文件的操作帮助类

    以上则为相关代码跟相关说明,欢迎各位朋友指点指点。

    以上代码,关于下载跟压缩的过程,应该是可以同步进行,而不需要分开的,现在正在做这个功能,等搞定之后会贴上来的。

  • 相关阅读:
    Assembly之instruction之CMP
    Assembly之Instruction之Byte and Word
    MSP430之section(1)
    MSP430之software development flow
    openMSP430之Custom linker script
    CDC之Synchronizers
    CDC之Metastability
    Embedded之Stack之三
    Embedded之Stack之二
    Embedded之Stack之一
  • 原文地址:https://www.cnblogs.com/loushuibazi/p/4018578.html
Copyright © 2020-2023  润新知