基于SharpZipLib实现带进度条压缩和解压缩文件

发布时间:2019-08-20
技术: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();
    }
}

三、项目结构图

image.png



本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码