基于SharpZipLib实现带进度条压缩和解压缩文件
技术:C#+Winform+SharpZipLib
概述
开源压缩库ICSharpCode.SharpZipLib实现批量压缩和解压缩多个文件和目录,使用进度条显示压缩和解压缩的进度。
详细
一、运行效果
二、实现过程
①、文件/目录选择
选择zip保存文件
SaveFileDialog saveFile = new SaveFileDialog(); saveFile.Filter = "zip files(*.zip)|*.zip"; if (saveFile.ShowDialog() == DialogResult.OK) { txtSaveZipFileName.Text = saveFile.FileName; if (!btnCompress.Enabled) btnCompress.Enabled = true; }
选择多个原始文件
OpenFileDialog openFile = new OpenFileDialog(); openFile.Multiselect = true; if (openFile.ShowDialog() == DialogResult.OK) lstFileName.Items.AddRange(openFile.FileNames);
选择解压到目录
FolderBrowserDialog folderBrowser = new FolderBrowserDialog(); if (folderBrowser.ShowDialog() == DialogResult.OK) lstFileName.Items.Add(folderBrowser.SelectedPath);
②、带进度报告功能的文件目录压缩/解压缩方法
批量压缩文件/目录
/// <summary> /// Pack ListBox Items /// </summary> /// <param name="lstFileName">The ListItems you want to zip</param> /// <param name="zipedFile">Target zipFile Path</param> /// <param name="changedDG">report process delegate</param> public void PackListItems(ListBox lstFileName, string zipedFile, ProcessChange changedDG) { if (lstFileName.Items.Contains(zipedFile)) { MessageBox.Show("原始文件不能包含最终的压缩文件!"); return; } using (FileStream ZipFile = File.Create(zipedFile)) { using (ZipOutputStream s = new ZipOutputStream(ZipFile)) { s.SetLevel(3); //0-9, 9 being the highest level of compression string key = Guid.NewGuid().ToString(); //Guid Key double totalCount = 0; foreach (string f in lstFileName.Items) { //总需要压缩的文件数量 if (File.Exists(f)) totalCount++; else if (Directory.Exists(f)) totalCount += Directory.GetFileSystemEntries(f, "*", SearchOption.AllDirectories).Count(); } ProcessItems.Add(key, new ProcessItem(totalCount)); List<FileSystemInfo> fsi = new List<FileSystemInfo>(); foreach (string f in lstFileName.Items) { //总需要压缩的文件数量 if (File.Exists(f)) fsi.Add(new FileInfo(f)); else if (Directory.Exists(f)) fsi.Add(new DirectoryInfo(f)); } PackSetp(fsi, s, key, zipedFile, changedDG); ProcessItems.Remove(key); s.Flush(); s.Close(); } } } /// <summary> /// 遍历FileSystemInfo对象数组 /// </summary> private void PackSetp(List<FileSystemInfo> fsiList, ZipOutputStream s, string processItemKey, string zipPath, ProcessChange changedDG) { foreach (FileSystemInfo fsi in fsiList) { if (fsi is DirectoryInfo) { DirectoryInfo di = fsi as DirectoryInfo; FileSystemInfo[] filenames = di.GetFileSystemInfos(); string pPath = di.Name + Path.DirectorySeparatorChar.ToString(); foreach (FileSystemInfo fs in filenames)// 遍历所有的文件和目录 { if (fs is DirectoryInfo)// 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件 { DirectoryInfo d = fs as DirectoryInfo; string file = d.FullName; PackSetp(file, s, pPath, processItemKey, zipPath, changedDG); changedDG?.Invoke(AddOneAndReport(processItemKey), file); } else if (fs is FileInfo)// 否则直接压缩文件 { FileInfo fi = fs as FileInfo; //打开压缩文件 using (FileStream fsm = fi.OpenRead()) { string file = fi.FullName; string fileName = pPath + Path.GetFileName(file); ZipEntry entry = new ZipEntry(fileName); entry.DateTime = DateTime.Now; entry.Size = fsm.Length; if (!this.IsKeepPath && fileName.Contains("\\")) { fileName = Path.GetFileName(fileName); if (ProcessItems[processItemKey].HandledFiles.Count(p => p == fileName) > 0) { changedDG(AddOneAndReport(processItemKey), file); continue; } } s.PutNextEntry(entry); byte[] buffer = new byte[fsm.Length]; int count = fsm.Read(buffer, 0, buffer.Length); while (count > 0) { s.Write(buffer, 0, count); count = fsm.Read(buffer, 0, buffer.Length); } fsm.Close(); changedDG?.Invoke(AddOneAndReport(processItemKey), file); ProcessItems[processItemKey].HandledFiles.Add(fileName); } } } } else if (fsi is FileInfo)// 否则直接压缩文件 { FileInfo fi = fsi as FileInfo; //打开压缩文件 using (FileStream fsm = fi.OpenRead()) { string file = fi.FullName; string fileName = Path.GetFileName(file); ZipEntry entry = new ZipEntry(fileName); entry.DateTime = DateTime.Now; entry.Size = fsm.Length; if (!this.IsKeepPath && fileName.Contains("\\")) { fileName = Path.GetFileName(fileName); if (ProcessItems[processItemKey].HandledFiles.Count(p => p == fileName) > 0) { changedDG(AddOneAndReport(processItemKey), file); continue; } } s.PutNextEntry(entry); byte[] buffer = new byte[fsm.Length]; int count = fsm.Read(buffer, 0, buffer.Length); while (count > 0) { s.Write(buffer, 0, count); count = fsm.Read(buffer, 0, buffer.Length); } fsm.Close(); changedDG?.Invoke(AddOneAndReport(processItemKey), file); ProcessItems[processItemKey].HandledFiles.Add(fileName); } } } }
批量解压缩zip文件
/// <summary> /// unPack zipFile Path List /// </summary> /// <param name="zipFilePathList">the list of the paths of zipFile</param> /// <param name="unzipPath">to Directory</param> /// <param name="changedDG">report process delegate</param> public void UnpackList(List<string> zipFilePathList, string unzipPath, ProcessChange changedDG) { //总需要压缩的文件数量 double totalCount = 0d; zipFilePathList.ForEach( (zipFilePath) => totalCount += GetZipFileCount(zipFilePath) ); string key = Guid.NewGuid().ToString(); //Guid Key ProcessItems.Add(key, new ProcessItem(totalCount)); zipFilePathList.ForEach( (zipFilePath) => UnpackFiles(zipFilePath, unzipPath, changedDG, "*", key) ); ProcessItems.Remove(key); } /// <summary> /// 解压基类 /// </summary> /// <param name="zipFilePath">压缩包文件路径</param> /// <param name="unzipPath">解压到的文件路径</param> /// <param name="changedDG">进度反馈委托</param> /// <param name="directoryName">解压指定的文件或文件夹,默认为空(所有)</param> private void UnpackFiles(string zipFilePath, string unzipPath, ProcessChange changedDG = null, string directName = "*", string processKey = "") { #region unzip if (unzipPath[unzipPath.Length - 1] != Path.DirectorySeparatorChar) { unzipPath = unzipPath + Path.DirectorySeparatorChar; } if (!Directory.Exists(unzipPath)) { Directory.CreateDirectory(unzipPath); } using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipFilePath))) { ZipEntry zipEntry = null; while ((zipEntry = zipStream.GetNextEntry()) != null) { zipEntry.CompressedSize = 9; string directoryName = Path.GetDirectoryName(zipEntry.Name); string fileName = Path.GetFileName(zipEntry.Name); if (!string.IsNullOrEmpty(directoryName)) { if (!Directory.Exists(unzipPath + directoryName)) { if (directName != "*" && !Path.HasExtension(directName) && !directoryName.StartsWith(directName)) { continue; } if (IsKeepPath) { Directory.CreateDirectory(unzipPath + directoryName); } } } if (!string.IsNullOrEmpty(fileName)) { if (zipEntry.CompressedSize == 0) break; if (zipEntry.IsDirectory) { directoryName = Path.GetDirectoryName(unzipPath + zipEntry.Name); } string zipFileName = !IsKeepPath ? Path.GetFileName(zipEntry.Name) : zipEntry.Name; if (directName != "*" && !Path.HasExtension(directName) && !zipEntry.Name.StartsWith(directName)) continue; if (Path.HasExtension(directName) && directName == zipEntry.Name) { HandleFile(unzipPath + zipFileName, zipStream, processKey, changedDG); return; } else if (!string.IsNullOrEmpty(directName) && !Path.HasExtension(directName)) { HandleFile(unzipPath + zipFileName, zipStream, processKey, changedDG); } } } } #endregion }
③、进度报告实现
进度信息存储类
using System.Collections.Generic; namespace WindowsFormsApplication1 { class ProcessItem { public ProcessItem(double NeedHandleCount) { this.NeedHandleCount = NeedHandleCount; HandledFiles = new List<string>(); } public double NeedHandleCount { set; get; } public double HadHandleCount { set; get; } public List<string> HandledFiles { set; get; } } }
带进度报告的压缩和解压缩方法调用
if (e.Argument.ToString() == "compression") { try { string toZip = txtSaveZipFileName.Text; handler.PackListItems(lstFileName, toZip, (num, file) => worker.ReportProgress((int)num, file)); //报告进度,和刚压缩完成的num为百分比,最大为100,可在此处写处理逻辑 } catch (Exception ex) { MessageBox.Show("压缩失败" + "\r\n" + ex.Message); } finally { worker.CancelAsync(); } } else { try { List<string> zipFilePathList = new List<string>(); foreach (string f in lstFileName.Items) { if (File.Exists(f) && Path.GetExtension(f) == ".zip") zipFilePathList.Add(f); } string unzipPath = txtExtractPath.Text; handler.UnpackList(zipFilePathList, unzipPath, (num, file) => worker.ReportProgress((int)num, file)); } catch (Exception ex) { MessageBox.Show("解压失败" + "\r\n" + ex.Message); } finally { worker.CancelAsync(); } }
三、项目结构图
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码