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; width: 200px; height: 20px;">
        <div id="pbar" style="height: 100%; background-color: #00ff00; width: 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:\temp】,則在最后增加"\"【D:\temp\】
    /// </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文件的操作幫助類

 

以上則為相關代碼跟相關說明,歡迎各位朋友指點指點。

 

以上代碼,關於下載跟壓縮的過程,應該是可以同步進行,而不需要分開的,現在正在做這個功能,等搞定之后會貼上來的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM