C# 通过ICSharpCode.SharpZipLib实现文件压缩下载
通过管理NuGet包添加ICSharpCode.SharpZipLib引用以完成,多文件或者文件夹压缩后下载效果
1、压缩文件实体类
/// <summary> /// 文件路径集合,文件名集合,压缩文件名 /// </summary> public class FileNameListZip { /// <summary> /// 文件路径集合,文件名集合 /// </summary> public Dictionary<string, string> fileDictionary { get; set; } /// <summary> /// 压缩文件名 /// </summary> public string fileZipName { get; set; } }
2、文件压缩帮助类
/// <summary> /// 压缩文件辅助类 /// </summary> public class ZipHelper { #region 压缩文件 /// <summary> /// 压缩单个文件 /// </summary> /// <param name="FileToZip">需要压缩的文件(绝对路径)</param> /// <param name="ZipedPath">压缩后的文件路径(绝对路径)</param> /// <param name="ZipedFileName">压缩后的文件名称(文件名,默认 同源文件同名)</param> /// <param name="CompressionLevel">压缩等级(0 无 - 9 最高,默认 5)</param> /// <param name="BlockSize">缓存大小(每次写入文件大小,默认 2048)</param> /// <param name="PassWord">加密密码(默认 123456)</param> /// <param name="IsEncrypt">是否加密(默认 不加密)</param> public static void ZipFile(string FileToZip, string ZipedPath, string ZipedFileName = "", int CompressionLevel = 5, int BlockSize = 2048, string PassWord = "123456", bool IsEncrypt = false) { //如果文件没有找到,则报错 if (!System.IO.File.Exists(FileToZip)) { throw new System.IO.FileNotFoundException("指定要压缩的文件: " + FileToZip + " 不存在!"); } //文件名称(默认同源文件名称相同) string ZipFileName = string.IsNullOrEmpty(ZipedFileName) ? ZipedPath + "\\" + new FileInfo(FileToZip).Name.Substring(0, new FileInfo(FileToZip).Name.LastIndexOf('.')) + ".zip" : ZipedPath + "\\" + ZipedFileName + ".zip"; using (System.IO.FileStream ZipFile = System.IO.File.Create(ZipFileName)) { using (ZipOutputStream ZipStream = new ZipOutputStream(ZipFile)) { using (System.IO.FileStream StreamToZip = new System.IO.FileStream(FileToZip, System.IO.FileMode.Open, System.IO.FileAccess.Read)) { string fileName = FileToZip.Substring(FileToZip.LastIndexOf("\\") + 1); ZipEntry ZipEntry = new ZipEntry(fileName); if (IsEncrypt) { //压缩文件加密 ZipStream.Password = PassWord; } ZipStream.PutNextEntry(ZipEntry); //设置压缩级别 ZipStream.SetLevel(CompressionLevel); //缓存大小 byte[] buffer = new byte[BlockSize]; int sizeRead = 0; try { do { sizeRead = StreamToZip.Read(buffer, 0, buffer.Length); ZipStream.Write(buffer, 0, sizeRead); } while (sizeRead > 0); } catch (System.Exception ex) { throw ex; } StreamToZip.Close(); } ZipStream.Finish(); ZipStream.Close(); } ZipFile.Close(); } } /// <summary> /// 压缩多个文件 /// </summary> /// <param name="filePathList">要进行压缩的文件路径</param> /// <param name="fileNameList">要进行压缩的文件名</param> /// <param name="zipedFilePath">压缩后生成的压缩所在文件夹</param> /// <param name="zipedFileName">压缩后生成的压缩文件名</param> /// <param name="Level">压缩等级(0 无 - 9 最高,默认 5)</param> public static void ZipFileList(List<string> filePathList, List<string> fileNameList,string zipedFilePath, string zipedFileName, int Level = 5) { FileNameListZip fileNameListZip = GetFileName(filePathList, fileNameList, zipedFilePath, zipedFileName); using (FileStream ZipFile = System.IO.File.Create(fileNameListZip.fileZipName)) { using (ZipOutputStream ZipStream = new ZipOutputStream(ZipFile)) { try { foreach (var fileToZip in fileNameListZip.fileDictionary) { string fileName = fileToZip.Value; using (FileStream fs = System.IO.File.OpenRead(fileToZip.Key)) { byte[] buffer = new byte[fs.Length]; fs.Read(buffer, 0, buffer.Length); fs.Close(); ZipEntry ZipEntry = new ZipEntry(fileName); ZipStream.PutNextEntry(ZipEntry); ZipStream.SetLevel(Level); ZipStream.Write(buffer, 0, buffer.Length); } } } finally { if (ZipStream != null) { ZipStream.Dispose(); ZipStream.Finish(); ZipStream.Close(); } } } } } /// <summary> /// 压缩文件夹 /// </summary> /// <param name="DirectoryToZip">需要压缩的文件夹(绝对路径)</param> /// <param name="ZipedPath">压缩后的文件路径(绝对路径)</param> /// <param name="ZipedFileName">压缩后的文件名称(文件名,默认 同源文件夹同名)</param> /// <param name="PassWord">压缩加密密码(默认 123456)</param> /// <param name="IsEncrypt">是否加密(默认 不加密)</param> public static void ZipDirectory(string DirectoryToZip, string ZipedPath, string ZipedFileName = "", string PassWord = "123456", bool IsEncrypt = false) { //如果目录不存在,则报错 if (!System.IO.Directory.Exists(DirectoryToZip)) { throw new System.IO.FileNotFoundException("指定的目录: " + DirectoryToZip + " 不存在!"); } //文件名称(默认同源文件名称相同) string ZipFileName = string.IsNullOrEmpty(ZipedFileName) ? ZipedPath + "\\" + new DirectoryInfo(DirectoryToZip).Name + ".zip" : ZipedPath + "\\" + ZipedFileName + ".zip"; System.IO.FileStream ZipFile = System.IO.File.Create(ZipFileName); ZipOutputStream s = new ZipOutputStream(ZipFile); if (IsEncrypt) { //压缩文件加密 s.Password = PassWord; } ZipSetp(DirectoryToZip, s, ""); } /// <summary> /// 压缩文件(并保存至服务器) /// </summary> /// <param name="filePathList">要压缩的所有文件(完全路径)</param> /// <param name="fileNameList">要压缩名称名称</param> /// <param name="zipedFileName">压缩后文件夹</param> /// <param name="zipedFileName">压缩后文件名称</param> /// <param name="Level">压缩级别</param> public static bool ZipFileMain(List<string> filePathList, List<string> fileNameList, string zipedFilePath, string zipedFileName, int Level = 5) { FileNameListZip fileNameListZip = GetFileName(filePathList, fileNameList, zipedFilePath, zipedFileName); ZipOutputStream s = new ZipOutputStream(System.IO.File.Create(fileNameListZip.fileZipName)); Crc32 crc = new Crc32(); //压缩级别 s.SetLevel(Level); try { foreach (var file in fileNameListZip.fileDictionary) { //打开压缩文件 FileStream fs = System.IO.File.OpenRead(file.Key); byte[] buffer = new byte[fs.Length]; fs.Read(buffer, 0, buffer.Length); //建立压缩实体 ZipEntry entry = new ZipEntry(System.IO.Path.GetFileName(file.Value)); //时间 entry.DateTime = DateTime.Now; //空间大小 entry.Size = fs.Length; fs.Close(); crc.Reset(); crc.Update(buffer); entry.Crc = crc.Value; s.PutNextEntry(entry); s.Write(buffer, 0, buffer.Length); } return true; } catch (Exception ex) { return false; } finally { s.Finish(); s.Close(); } } /// <summary> /// 压缩多个文件/文件夹 /// </summary> /// <param name="sourceList">源文件/文件夹路径列表</param> /// <param name="zipFilePath">压缩文件路径</param> /// <param name="comment">注释信息</param> /// <param name="password">压缩密码</param> /// <param name="compressionLevel">压缩等级,范围从0到9,可选,默认为6</param> /// <param name="BufferSize">分段大小默认1024</param> /// <returns></returns> public static bool CompressFile(IEnumerable<string> sourceList, string zipFilePath, string comment = null, string password = null, int compressionLevel = 6, int BufferSize = 1024) { bool result = false; try { //检测目标文件所属的文件夹是否存在,如果不存在则建立 string zipFileDirectory = Path.GetDirectoryName(zipFilePath); if (!Directory.Exists(zipFileDirectory)) { Directory.CreateDirectory(zipFileDirectory); } Dictionary<string, string> dictionaryList = PrepareFileSystementities(sourceList); using (ZipOutputStream zipStream = new ZipOutputStream(System.IO.File.Create(zipFilePath))) { zipStream.Password = password;//设置密码 zipStream.SetComment(comment);//添加注释 zipStream.SetLevel(compressionLevel);//设置压缩等级 foreach (string key in dictionaryList.Keys)//从字典取文件添加到压缩文件 { if (System.IO.File.Exists(key))//判断是文件还是文件夹 { FileInfo fileItem = new FileInfo(key); using (FileStream readStream = fileItem.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) { ZipEntry zipEntry = new ZipEntry(dictionaryList[key]); zipEntry.DateTime = fileItem.LastWriteTime; zipEntry.Size = readStream.Length; zipStream.PutNextEntry(zipEntry); int readLength = 0; byte[] buffer = new byte[BufferSize]; do { readLength = readStream.Read(buffer, 0, BufferSize); zipStream.Write(buffer, 0, readLength); } while (readLength == BufferSize); readStream.Close(); } } else//对文件夹的处理 { ZipEntry zipEntry = new ZipEntry(dictionaryList[key] + "/"); zipStream.PutNextEntry(zipEntry); } } zipStream.Flush(); zipStream.Finish(); zipStream.Close(); } result = true; } catch (System.Exception ex) { throw new Exception("压缩文件失败", ex); } return result; } #endregion 压缩文件 #region 解压 /// <summary> /// 解压一个zip文件 /// </summary> /// <param name="ZipFile">需要解压的Zip文件(绝对路径)</param> /// <param name="TargetDirectory">解压到的目录</param> /// <param name="Password">解压密码</param> /// <param name="OverWrite">是否覆盖已存在的文件</param> public static void UnZip(string ZipFile, string TargetDirectory, string Password, bool OverWrite = true) { //如果解压到的目录不存在,则报错 if (!System.IO.Directory.Exists(TargetDirectory)) { throw new System.IO.FileNotFoundException("指定的目录: " + TargetDirectory + " 不存在!"); } //目录结尾 if (!TargetDirectory.EndsWith("\\")) { TargetDirectory = TargetDirectory + "\\"; } ZipInputStream zipfiles = new ZipInputStream(System.IO.File.OpenRead(ZipFile)); if (!string.IsNullOrWhiteSpace(Password)) { zipfiles.Password = Password; } ZipEntry theEntry; while ((theEntry = zipfiles.GetNextEntry()) != null) { string directoryName = ""; string pathToZip = ""; pathToZip = theEntry.Name; if (pathToZip != "") { directoryName = Path.GetDirectoryName(pathToZip) + "\\"; } string fileName = Path.GetFileName(pathToZip); Directory.CreateDirectory(TargetDirectory + directoryName); if (fileName != "") { if ((System.IO.File.Exists(TargetDirectory + directoryName + fileName) && OverWrite) || (!System.IO.File.Exists(TargetDirectory + directoryName + fileName))) { using (FileStream streamWriter = System.IO.File.Create(TargetDirectory + directoryName + fileName)) { int size = 2048; byte[] data = new byte[2048]; while (true) { size = zipfiles.Read(data, 0, data.Length); if (size > 0) streamWriter.Write(data, 0, size); else break; } streamWriter.Close(); } } } } zipfiles.Close(); } /// <summary> /// 解压文件到指定文件夹 /// </summary> /// <param name="sourceFile">压缩文件</param> /// <param name="destinationDirectory">目标文件夹,如果为空则解压到当前文件夹下</param> /// <param name="password">密码</param> /// <param name="BufferSize">分段大小</param> /// <returns></returns> public static bool DecomparessFile(string sourceFile, string destinationDirectory = null, string password = null, int BufferSize = 1024) { bool result = false; if (!System.IO.File.Exists(sourceFile)) { throw new FileNotFoundException("要解压的文件不存在", sourceFile); } if (string.IsNullOrWhiteSpace(destinationDirectory)) { destinationDirectory = Path.GetDirectoryName(sourceFile); } try { if (!Directory.Exists(destinationDirectory)) { Directory.CreateDirectory(destinationDirectory); } using (ZipInputStream zipStream = new ZipInputStream(System.IO.File.Open(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read))) { zipStream.Password = password; ZipEntry zipEntry = zipStream.GetNextEntry(); while (zipEntry != null) { if (zipEntry.IsDirectory)//如果是文件夹则创建 { Directory.CreateDirectory(Path.Combine(destinationDirectory, Path.GetDirectoryName(zipEntry.Name))); } else { string fileName = Path.GetFileName(zipEntry.Name); if (!string.IsNullOrEmpty(fileName) && fileName.Trim().Length > 0) { FileInfo fileItem = new FileInfo(Path.Combine(destinationDirectory, zipEntry.Name)); using (FileStream writeStream = fileItem.Create()) { byte[] buffer = new byte[BufferSize]; int readLength = 0; do { readLength = zipStream.Read(buffer, 0, BufferSize); writeStream.Write(buffer, 0, readLength); } while (readLength == BufferSize); writeStream.Flush(); writeStream.Close(); } fileItem.LastWriteTime = zipEntry.DateTime; } } zipEntry = zipStream.GetNextEntry();//获取下一个文件 } zipStream.Close(); } result = true; } catch (System.Exception ex) { throw new Exception("文件解压发生错误", ex); } return result; } #endregion #region 辅助方法 /// <summary> /// 处理文件名 /// </summary> /// <param name="filePathList">文件地址集合</param> /// <param name="fileNameList">文件名集合</param> /// <param name="zipFilePath">压缩包地址</param> /// <param name="zipedFile">压缩包名称</param> /// <returns></returns> public static FileNameListZip GetFileName(List<string> filePathList, List<string> fileNameList, string zipFilePath, string zipedFile) { ///文件重名处理 Dictionary<string, int> dictionary = new Dictionary<string, int>(); //文件路径与文件名字典 Dictionary<string, string> fileDictionary = new Dictionary<string, string>(); string fileZipName = string.Empty; FileNameListZip fileNameListZip = new FileNameListZip(); if (filePathList != null && filePathList.Count > 0) { for (int i = 0; i < filePathList.Count; i++) { if (System.IO.File.Exists(filePathList[i])) { string filename = Path.GetFileName(fileNameList[i]);//返回带扩展名的文件名 "default.avi" string extension = Path.GetExtension(fileNameList[i]);//扩展名 ".aspx" string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileNameList[i]);// 没有扩展名的文件名 "default" if (dictionary.ContainsKey(filename)) { var count = dictionary[filename] + 1; dictionary[filename] = count; var name = fileNameWithoutExtension + "(" + count + ")" + extension; fileDictionary.Add(filePathList[i], name); } else { dictionary.Add(filename, 1); fileDictionary.Add(filePathList[i], filename); } } } fileNameListZip.fileDictionary = fileDictionary; if (!Directory.Exists(zipFilePath)) { Directory.CreateDirectory(zipFilePath); } fileNameListZip.fileZipName = zipFilePath + "\\" + zipedFile; } return fileNameListZip; } /// <summary> /// 递归遍历目录 /// </summary> private static void ZipSetp(string strDirectory, ZipOutputStream s, string parentPath) { if (strDirectory[strDirectory.Length - 1] != Path.DirectorySeparatorChar) { strDirectory += Path.DirectorySeparatorChar; } Crc32 crc = new Crc32(); string[] filenames = Directory.GetFileSystemEntries(strDirectory); foreach (string file in filenames)// 遍历所有的文件和目录 { if (Directory.Exists(file))// 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件 { string pPath = parentPath; pPath += file.Substring(file.LastIndexOf("\\") + 1); pPath += "\\"; ZipSetp(file, s, pPath); } else // 否则直接压缩文件 { //打开压缩文件 using (FileStream fs = System.IO.File.OpenRead(file)) { byte[] buffer = new byte[fs.Length]; fs.Read(buffer, 0, buffer.Length); string fileName = parentPath + file.Substring(file.LastIndexOf("\\") + 1); ZipEntry entry = new ZipEntry(fileName); entry.DateTime = DateTime.Now; entry.Size = fs.Length; fs.Close(); crc.Reset(); crc.Update(buffer); entry.Crc = crc.Value; s.PutNextEntry(entry); s.Write(buffer, 0, buffer.Length); } } } } /// <summary> /// 为压缩准备文件系统对象 /// </summary> /// <param name="sourceFileEntityPathList"></param> /// <returns></returns> private static Dictionary<string, string> PrepareFileSystementities(IEnumerable<string> sourceFileEntityPathList) { Dictionary<string, string> fileEntityDictionary = new Dictionary<string, string>();//文件字典 string parentDirectoryPath = ""; foreach (string fileEntityPath in sourceFileEntityPathList) { string path = fileEntityPath; //保证传入的文件夹也被压缩进文件 if (path.EndsWith(@"\")) { path = path.Remove(path.LastIndexOf(@"\")); } parentDirectoryPath = Path.GetDirectoryName(path) + @"\"; if (parentDirectoryPath.EndsWith(@":\\"))//防止根目录下把盘符压入的错误 { parentDirectoryPath = parentDirectoryPath.Replace(@"\\", @"\"); } //获取目录中所有的文件系统对象 Dictionary<string, string> subDictionary = GetAllFileSystemEntities(path, parentDirectoryPath); //将文件系统对象添加到总的文件字典中 foreach (string key in subDictionary.Keys) { if (!fileEntityDictionary.ContainsKey(key))//检测重复项 { fileEntityDictionary.Add(key, subDictionary[key]); } } } return fileEntityDictionary; } /// <summary> /// 获取所有文件系统对象 /// </summary> /// <param name="source">源路径</param> /// <param name="topDirectory">顶级文件夹</param> /// <returns>字典中Key为完整路径,Value为文件(夹)名称</returns> private static Dictionary<string, string> GetAllFileSystemEntities(string source, string topDirectory) { Dictionary<string, string> entitiesDictionary = new Dictionary<string, string>(); entitiesDictionary.Add(source, source.Replace(topDirectory, "")); if (Directory.Exists(source)) { //一次性获取下级所有目录,避免递归 string[] directories = Directory.GetDirectories(source, "*.*", SearchOption.AllDirectories); foreach (string directory in directories) { entitiesDictionary.Add(directory, directory.Replace(topDirectory, "")); } string[] files = Directory.GetFiles(source, "*.*", SearchOption.AllDirectories); foreach (string file in files) { entitiesDictionary.Add(file, file.Replace(topDirectory, "")); } } return entitiesDictionary; } #endregion }
3、文件下载帮助类,文件压缩下载方法为DownLoadoldZip
/// <summary> /// 文件下载帮助类 /// </summary> public class DownLoadoldHelper { #region 辅助方法 /// <summary> /// 参数为虚拟路径 /// </summary> public static string FileNameExtension(string FileName) { return Path.GetExtension(MapPathFile(FileName)); } /// <summary> /// 获取物理地址 /// </summary> public static string MapPathFile(string FileName) { return HttpContext.Current.Server.MapPath(FileName); } /// <summary> /// 验证文件是否存在 /// </summary> /// <param name="FileName"></param> /// <returns></returns> public static bool FileExists(string FileName) { string destFileName = FileName; if (System.IO.File.Exists(destFileName)) { return true; } else { return false; } } #endregion #region 普通下载 /// <summary> /// 普通下载 /// </summary> /// <param name="FileName">文件虚拟路径</param> /// /// <param name="name">返回客户端名称</param> public static void DownLoadold(string FileName, string name) { string destFileName = FileName; if (System.IO.File.Exists(destFileName)) { FileInfo fi = new FileInfo(destFileName); HttpContext.Current.Response.Clear(); HttpContext.Current.Response.ClearHeaders(); HttpContext.Current.Response.Buffer = false; HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(name, System.Text.Encoding.UTF8)); HttpContext.Current.Response.AppendHeader("Content-Length", fi.Length.ToString()); HttpContext.Current.Response.ContentType = "application/octet-stream"; HttpContext.Current.Response.WriteFile(destFileName); HttpContext.Current.Response.Flush(); HttpContext.Current.Response.End(); } } #endregion #region 多文件压缩并下载 /// <summary> /// 批量下载(压缩包形式) /// </summary> /// <param name="filePathList">路径</param> /// <param name="fileNameList">文件名</param> /// <param name="fileSizeList">文件大小(字节)</param> /// <param name="zipFilePath">压缩包地址</param> /// <param name="zipFileName">压缩包名称</param> public static void DownLoadoldZip(List<string> filePathList, List<string> fileNameList, List<string> fileSizeList, string zipFilePath, string zipFileName) { //处理文件地址名,文件名,压缩后文件名 FileNameListZip fileNameListZip = ZipHelper.GetFileName(filePathList, fileNameList, zipFilePath, zipFileName); #region 清除对应压缩包文件夹下,时间早于3天前的所有压缩包 //获取文件夹下所有文件及子文件夹 string[] zipFilePathList = Directory.GetFiles(zipFilePath); if (zipFilePathList != null && zipFilePathList.Length > 0) { //循环该文件夹下所有文件 foreach (var file in zipFilePathList) { //判断文件是否存在 if (System.IO.File.Exists(file)) { FileInfo fileInfo = new FileInfo(file); var createTime = fileInfo.CreationTime;//获取文件创建时间 //var firstWork = DateTime.Now.AddDays(0 - Convert.ToInt32(DateTime.Now.DayOfWeek) - 7);//获取当前时间的上周日 var firstWork = DateTime.Now.AddDays(-3);//获取当前时间的3天前当前时间 var compNum = DateTime.Compare(createTime, firstWork);//比较文件创建时间与当前时间的3天前时间 if (compNum < 0)//创建时间早于3天前 { fileInfo.Delete();//永久删除文件 } } } } #endregion 清除对应压缩包文件夹下,时间早于3天前的所有压缩包 #region 生产压缩包实体文件并下载 ZipHelper.ZipFileList(filePathList, fileNameList, zipFilePath, zipFileName); DownLoadByPath(fileNameListZip.fileZipName); #endregion 生产压缩包实体文件并下载 } /// <summary> /// 下载文件,根据路径 /// </summary> /// <param name="filePath">文件物理地址</param> public static void DownLoadByPath(string filePath) { long chunkSize = 204800; //指定块大小 byte[] buffer = new byte[chunkSize]; //建立一个200K的缓冲区 long dataToRead = 0; //已读的字节数 FileStream stream = null; try { //打开文件 stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); dataToRead = stream.Length; //添加Http头 HttpContext.Current.Response.ContentType = "application/octet-stream"; HttpContext.Current.Response.AddHeader("Content-Disposition", "attachement;filename=" + HttpUtility.UrlEncode(Path.GetFileName(filePath), System.Text.Encoding.UTF8)); HttpContext.Current.Response.AddHeader("Content-Length", dataToRead.ToString()); while (dataToRead > 0) { if (HttpContext.Current.Response.IsClientConnected) { int length = stream.Read(buffer, 0, Convert.ToInt32(chunkSize)); HttpContext.Current.Response.OutputStream.Write(buffer, 0, length); HttpContext.Current.Response.Flush(); HttpContext.Current.Response.Clear(); dataToRead -= length; } else { dataToRead = -1; //防止client失去连接 } } } catch (Exception ex) { HttpContext.Current.Response.Write("Error:" + ex.Message); } finally { if (stream != null) stream.Close(); HttpContext.Current.Response.Close(); } } #endregion }
具体调用如图所示
生成压缩文件如图:
并在压缩下载DownLoadoldZip方法中,我这里做了只保留三天内的压缩文件,当文件是在当前时间的三天前生成的则删掉,以免后续文件越来越多占用不必要的内存
本文来自博客园,作者:流纹,转载请注明原文链接:https://www.cnblogs.com/lwk9527/p/17374168.html