先上效果图,大家看看
总体效果如上所示,至于为什么会有两个按钮,是因为一个是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" %>图片下载
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)); } ////// 根据用户ID,创建此次下载,用户需要涉及到的文件信息 /// /// 用户ID ///public Dictionary 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 iniParams = new Dictionary (); 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 userParams = new Dictionary (); 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; } /// /// 下载图片数据 /// /// 用户目录 [AjaxPro.AjaxMethod] public DictionaryGetImageData(string uid) { Dictionary userInfo = CreateUserFolderInfo(uid); // 获取出卡口图片列表 KaKouBLL kkb = new KaKouBLL(); DataTable dt = kkb.GetXmlSqlByParams(0, 10, false, " TGSJ > to_date('2014-09-25 00:00:00','yyyy-MM-dd hh24:mi:ss') and TGSJ < to_date('2014-09-25 23:59:59','yyyy-MM-dd hh24:mi:ss') ", "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; } ////// 线程启动需要执行的任务 /// /// public void ThreadMethod(Object o) { try { DictionaryuserParams = o as Dictionary ; 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; } } /// /// 将图片下载到指定位置 /// /// 图片的URL /// 本地磁盘位置及文件名 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; } } ////// 读取ini配置文件的进度信息 /// /// ini文件路径 /// 标识项 /// 标识符 ///查询结果 [AjaxPro.AjaxMethod] public DictionaryReadProgress(string url, Dictionary ops, string Iden) { Dictionary returnDic = new Dictionary (); foreach (string item in ops.Keys) { returnDic.Add(item, IniFileControl.ReadString(item, Iden, url)); } return returnDic; } /// /// 服务器按钮下载事件。用来下载压缩文件 /// 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;//////ZipManager 的摘要说明/// 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文件检测 ////// 操作ini配置文件参数 /// /// 路径 /// 标识项 /// 标识符 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; } } ////// 压缩文件 /// /// /// 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(); } ////// 将文件转换为流压缩进压缩文件 /// /// 需要压缩的路径 /// 需要压缩的文件夹名称 /// 现有的源ZipOutputStream /// out j为已添加“ZipEntry”的“ZipOutputStream” 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” } ////// 若路径为【D:\temp】,则在最后增加"\"【D:\temp\】 /// /// ///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;//////IniFileControl 的摘要说明/// 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); ////// 写INI文件 /// /// 标识项 /// 标识符 /// 值 /// ini文件路径 public static void WriteString(string section, string ident, string value, string filePath) { if (!WritePrivateProfileString(section, ident, value, filePath)) { throw (new ApplicationException("写Ini文件出错")); } } ////// 读取INI文件指定 /// /// 标识项 /// 标识符 /// ini文件路径 ///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(); }}
以上则为相关代码跟相关说明,欢迎各位朋友指点指点。
以上代码,关于下载跟压缩的过程,应该是可以同步进行,而不需要分开的,现在正在做这个功能,等搞定之后会贴上来的。