使用SharpZipLib实现文件压缩、解压

时间:2022-05-24 18:34:20

接口

public interface IUnZip
{
    /// <summary>   
    /// 功能:解压zip格式的文件。   
    /// </summary>   
    /// <param name="zipFilePath">压缩文件路径</param>   
    /// <param name="unZipDir">解压文件存放路径,为空时默认与压缩文件同一级目录下,跟压缩文件同名的文件夹</param>   
    /// <param name="password">压缩包密码</param>
    /// <returns>解压后文件所在的文件夹</returns>
    string UnZipFile(string zipFilePath, string unZipDir = null, string password = null);
}

public interface IZip
{
    /// <summary>
    /// 将选定的文件压入一个目标zip中
    /// </summary>
    /// <param name="list">选定的文件/文件夹(路径的集合)</param>
    /// <param name="targetFileName">压缩后得到的zip保存路径</param> 
    /// <param name="password">压缩包密码</param>
    /// <param name="overwrite">如果Zip文件已存在,是否覆盖</param> 
    /// <param name="level">压缩等级0—9</param>
    /// <returns>压缩包路径</returns>
    void Compress(List<string> list, string targetFileName, string password = null, bool overwrite = true, int level = 9);

    /// <summary>
    /// 将选定的文件压入一个目标zip中
    /// </summary>
    /// <param name="fileOrDir">选定的文件/文件夹</param>
    /// <param name="targetFileName">压缩后得到的zip保存路径</param>
    /// <param name="password">压缩包密码</param>
    /// <param name="overwrite">如果Zip文件已存在,是否覆盖</param>  
    /// <param name="level">压缩等级0—9</param>
    /// <returns>压缩包路径</returns>
    void Compress(string fileOrDir, string targetFileName, string password = null, bool overwrite = true, int level = 9);
}

public interface IZipHelper:IZip,IUnZip
{
}

实现

   public class ZipHelper : IZipHelper
{
    #region 压缩文件

    /// <inheritdoc/>
    public void Compress(string fileOrDir, string targetFileName, string password = null, bool overwrite = true, int level = 9)
    {
        List<string> list = new List<string> { fileOrDir };
        Compress(list, targetFileName, password, overwrite,level);
    }

    /// <inheritdoc/>
    public void Compress(List<string> list, string targetFileName, string password = null, bool overwrite = true,int level = 9)
    {
        CheckForCompress(list, targetFileName, overwrite);

        //如果已经存在目标文件,删除
        if (File.Exists(targetFileName))
        {
            File.Delete(targetFileName);
        }

        ZipOutputStream zips = null;
        FileStream fileStream = null;
        try
        {
            fileStream = File.Create(targetFileName);
            zips = new ZipOutputStream(fileStream);
            zips.SetLevel(level % 10);      //压缩等级
            zips.Password = password;
            foreach (string dir in list)
            {
                if (File.Exists(dir))
                {
                    AddFile("",dir, zips);
                }
                else
                {
                    CompressFolder("", dir, zips);
                }
            }
            zips.Finish();
        }
        catch { throw; }
        finally
        {
            if(fileStream!= null)
            {
                fileStream.Close();
                fileStream.Dispose();
            }
            if(zips!= null)
            {
                zips.Close();
                zips.Dispose();
            }
        }
    }

    #region private
    private void CheckForCompress(List<string> files, string targetFileName, bool overwrite)
    {
        //因为files可能来自不同的文件夹,所以不方便自动提供一个默认文件夹,需要提供
        if (!overwrite && File.Exists(targetFileName))
        {
            throw new Exception("目标zip文件已存在!");
        }

        //待压入的文件或文件夹需要真实存在
        foreach (var item in files)
        {
            if (!File.Exists(item) && !Directory.Exists(item))
            {
                throw new Exception($"文件/文件夹【{item}】不存在!");
            }
        }

        //不能有同名的文件/文件夹
        Dictionary<string, string> dic = new Dictionary<string, string>();
        foreach (var item in files)
        {
            string item_ = item.TrimEnd('/', '\\');
            string fileName = Path.GetFileName(item_);
            if (dic.ContainsKey(fileName))
            {
                throw new Exception($"选中的文件/文件夹中存在同名冲突:【{dic[fileName]}】,【{item_}】");
            }
            else
            {
                dic[fileName] = item_;
            }
        }
    }
    
    private void AddFile(string orignalDir, string file, ZipOutputStream zips)
    {  
        //文件
        FileStream StreamToZip = null;
        try
        {
            //加入ZIP文件条目(为压缩文件流提供一个容器)
            StreamToZip = new FileStream(file, FileMode.Open, FileAccess.Read);
            string fileName = Path.GetFileName(file);
            if (!string.IsNullOrEmpty(orignalDir))
            {
                fileName = orignalDir + Path.DirectorySeparatorChar + fileName;
            }
            ZipEntry z = new ZipEntry(fileName);
            zips.PutNextEntry(z);

            //写入文件流
            int pack = 10240; //10Kb
            byte[] buffer = new byte[pack];

            int size = StreamToZip.Read(buffer, 0, buffer.Length);
            while (size > 0)
            {
                zips.Write(buffer, 0, size);
                size = StreamToZip.Read(buffer, 0, buffer.Length);
            }
        }
        catch { throw; }
        finally
        {
            if (StreamToZip != null)
            {
                StreamToZip.Close();
                StreamToZip.Dispose();
            }
        }
    }
    private void AddFolder(string orignalDir, string folder, ZipOutputStream zips)
    {
        //文件夹
        folder = folder.TrimEnd('/','\\');
        string fileName = Path.GetFileName(folder);
        if (!string.IsNullOrEmpty(orignalDir))
        {
            fileName = orignalDir + Path.DirectorySeparatorChar + fileName ;
        }
        fileName += Path.DirectorySeparatorChar;
        ZipEntry z = new ZipEntry(fileName);
        zips.PutNextEntry(z);
    }
    /// <summary>
    /// 递归压缩文件夹内所有文件和子文件夹
    /// </summary>
    /// <param name="orignalDir">外层文件夹</param>
    /// <param name="dir">被压缩文件夹</param>
    /// <param name="zips">流</param>
    private void CompressFolder(string orignalDir,string dir, ZipOutputStream zips)
    {
        // 压缩当前文件夹下所有文件
        string[] names = Directory.GetFiles(dir);
        foreach (string fileName in names)
        {
            AddFile(orignalDir,fileName, zips);
        }
        // 压缩子文件夹
        names = Directory.GetDirectories(dir);
        foreach (string folderName in names)
        {
            AddFolder(orignalDir, folderName, zips);

            string _orignalDir = Path.GetFileName(folderName);
            if (!string.IsNullOrEmpty(orignalDir))
            {
                _orignalDir = orignalDir + Path.DirectorySeparatorChar + _orignalDir;
            }
            CompressFolder(_orignalDir, folderName, zips);
        }
    }
    #endregion private

    #endregion 压缩文件

    #region 解压文件

    /// <inheritdoc/>
    public string UnZipFile(string zipFilePath, string unZipDir = null,string password = null)
    {
        if (!File.Exists(zipFilePath))
        {
            throw new Exception($"压缩文件【{zipFilePath}】不存在!");
        }
        //解压文件夹为空时默认与压缩文件同一级目录下,跟压缩文件同名的文件夹   
        if (string.IsNullOrWhiteSpace(unZipDir))
        {
            unZipDir = Path.GetDirectoryName(zipFilePath);
            string name = Path.GetFileNameWithoutExtension(zipFilePath);
            unZipDir = Path.Combine(unZipDir, name);
        }

        string unZipDir2 = unZipDir;
        char lastChar = unZipDir[unZipDir.Length - 1];
        if (lastChar != '/' && lastChar != '\\')
        {
            unZipDir += Path.DirectorySeparatorChar;
        }

        if (!Directory.Exists(unZipDir))
            Directory.CreateDirectory(unZipDir);

        //解压
        UnZipProcess(zipFilePath, unZipDir, password);

        return unZipDir2;
    }
    private void UnZipProcess(string zipFilePath, string unZipDir, string password)
    {
        ZipInputStream zipInput = null;
        FileStream fileStream = null;
        try
        {
            fileStream = File.OpenRead(zipFilePath);
            zipInput = new ZipInputStream(fileStream);
            zipInput.Password = password;
            ZipEntry theEntry;
            while ((theEntry = zipInput.GetNextEntry()) != null)
            {
                string tempPath = unZipDir + theEntry.Name;
                if (theEntry.IsDirectory)
                {
                    if (!Directory.Exists(tempPath))
                    {
                        Directory.CreateDirectory(tempPath);
                    }
                }
                else
                {
                    using (FileStream streamWriter = File.Create(tempPath))
                    {
                        byte[] buffer = new byte[10240];
                        int size = zipInput.Read(buffer, 0, buffer.Length);
                        while (size > 0)
                        {
                            streamWriter.Write(buffer, 0, size);
                            size = zipInput.Read(buffer, 0, buffer.Length);
                        }
                    }
                }
            }
        }
        catch
        {
            throw;
        }
        finally
        {
            if (fileStream != null)
            {
                fileStream.Close();
                fileStream.Dispose();
            }
            if (zipInput != null)
            {
                zipInput.Close();
                zipInput.Dispose();
            }
        }
    }
      
    #endregion
}