压缩、解压缩zip文件 ZipArchive

Demo

ZipArchiveHelper.CreateZipFileFromDirectory(srcDir, zipFile);
......
ZipArchiveHelper.UnZip(zipFile, tempDir);
ZipArchiveHelper.CopyDirectory(tempDir, dstDir);
ZipArchiveHelper.DeleteFolder(tempDir);
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text.RegularExpressions;

public static class ZipArchiveHelper
{
    /// <summary>
    /// 创建 zip 存档,该存档包括指定目录的文件和目录,使用指定压缩级别,以及可以选择包含基目录。
    /// </summary>
    /// <param name="srcDirectory">要存档的目录或文件</param>
    /// <param name="dstFileName">要生成的文件(当前目录或绝对路径)</param>
    /// <param name="compressionLevel">压缩级别</param>
    /// <param name="bIncludeBaseDiretory">压缩包中是否包含父目录</param>
    /// <returns></returns>
    public static bool CreateZipFileFromDirectory(string srcDirectory, string dstFileName, CompressionLevel compressionLevel = CompressionLevel.Fastest, bool bIncludeBaseDiretory = true)
    {
        try
        {
            if (Directory.Exists(srcDirectory))
            {
                if (!File.Exists(dstFileName))
                {
                    ZipFile.CreateFromDirectory(srcDirectory, dstFileName, compressionLevel, bIncludeBaseDiretory);
                }
                else
                {
                    var infoDic = GetAllDirList(srcDirectory, bIncludeBaseDiretory);
                    using (var archive = ZipFile.Open(dstFileName, ZipArchiveMode.Update))
                    {
                        foreach (var key in infoDic.Keys)
                        {
                            if (key != dstFileName)
                            {
                                var fileName = Path.GetFileName(key);
                                var entryList = new List<ZipArchiveEntry>();
                                foreach (var entry in archive.Entries)
                                {
                                    if (fileName != null && (entry.FullName.StartsWith(fileName) || fileName.StartsWith(entry.FullName)))
                                    {
                                        entryList.Add(entry);
                                    }
                                }
                                entryList.ForEach(x => x.Delete());
                                archive.CreateEntryFromFile(key, infoDic[key], compressionLevel);
                            }
                        }
                    }
                }
            }
            else if (File.Exists(srcDirectory))
            {
                if (!File.Exists(dstFileName))
                {
                    ZipFile.CreateFromDirectory(srcDirectory, dstFileName, compressionLevel, false);
                }
                else
                {
                    using (var archive = ZipFile.Open(dstFileName, ZipArchiveMode.Update))
                    {
                        if (srcDirectory != dstFileName)
                        {
                            var fileName = Path.GetFileName(srcDirectory);
                            var entryList = new List<ZipArchiveEntry>();
                            foreach (var entry in archive.Entries)
                            {
                                if (fileName != null && (entry.FullName.StartsWith(fileName) || fileName.StartsWith(entry.FullName)))
                                {
                                    entryList.Add(entry);
                                }
                            }
                            entryList.ForEach(x => x.Delete());
                            archive.CreateEntryFromFile(srcDirectory, fileName, compressionLevel);
                        }
                    }
                }
            }
            else
            {
                return false;
            }
            return true;
        }
        catch (Exception ex)
        {
            string err = ex.Message;
            return false;
        }
    }
    /// <summary>
    /// 获取目录下所有[文件名,要压缩的相对文件名]字典
    /// </summary>
    /// <param name="srcDirectory"></param>
    /// <param name="bIncludeBaseDiretory"></param>
    /// <param name="prefix"></param>
    /// <returns></returns>
    private static Dictionary<string, string> GetAllDirList(string srcDirectory, bool bIncludeBaseDiretory = false, string prefix = "")
    {
        var rslt = new Dictionary<string, string>();
        var info = new DirectoryInfo(srcDirectory);
        if (bIncludeBaseDiretory)
        {
            prefix += info.Name + "\\";
        }
        foreach (var dir in info.GetDirectories())
        {
            rslt = rslt.Concat(GetAllDirList(dir.FullName, true, prefix)).ToDictionary(k => k.Key, k => k.Value);
            foreach (var file in info.GetFiles())
            {
                if (!rslt.ContainsKey(file.FullName))
                {
                    rslt.Add(file.FullName, prefix + info.Name);
                }
            }
        }
        return rslt;
    }

    public static bool UnZip(string zipFile, string dstDir)
    {
        bool rslt = false;
        try
        {
            dstDir = dstDir.EndsWith(@"\") ? dstDir : dstDir + @"\";
            var info = new DirectoryInfo(dstDir);
            if (!info.Exists)
            {
                info.Create();
            }
            var fi = new FileInfo(zipFile);
            if (!fi.Exists)
            {
                return false;
            }
            using (var fs = new FileStream(zipFile, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
            {
                using (var archive = new ZipArchive(fs, ZipArchiveMode.Read))
                {
                    foreach (var entry in archive.Entries)
                    {
                        if (!entry.FullName.EndsWith("/"))
                        {
                            var entryFilePath = Regex.Replace(entry.FullName.Replace("/", @"\"), @"^\\*", "");
                            var filePath = info + entryFilePath;
                            var content = new byte[entry.Length];
                            entry.Open().Read(content, 0, content.Length);
                            if (File.Exists(filePath) && content.Length == new FileInfo(filePath).Length)
                            {
                                // 跳过相同的文件,否则覆盖更新
                                continue;
                            }
                            var sameInfo = new DirectoryInfo(filePath);
                            if (sameInfo.Exists)
                            {
                                sameInfo.Delete(true);
                                DeleteDirectoryWithCmd(filePath);
                            }
                            var sameFi = new FileInfo(filePath);
                            if (sameFi.Exists)
                            {
                                sameFi.Delete();
                                DeleteFileWithCmd(filePath);
                            }
                            var parentInfo = Directory.GetParent(filePath);
                            if (!parentInfo.Exists)
                            {
                                parentInfo.Create();
                            }
                            File.WriteAllBytes(filePath, content);
                        }
                    }
                }
            }
            rslt = true;
        }
        catch (Exception ex)
        {
            string err = ex.Message;
            return false;
        }
        return rslt;
    }
    /// <summary>
    /// 调用bat删除目录,以防止系统底层的异步删除机制
    /// </summary>
    /// <param name="dir"></param>
    private static bool DeleteFileWithCmd(string dir)
    {
        var p = new Process();
        var info = new ProcessStartInfo("CMD.EXE", "/C rd /S /Q \"" + dir + "\"")
        {
            UseShellExecute = false,
            RedirectStandardOutput = true,
        };
        p.StartInfo = info;
        p.Start();
        p.WaitForExit();
        var output = p.StandardOutput.ReadToEnd();
        if (string.IsNullOrWhiteSpace(output))
        {
            return true;
        }
        return false;
    }
    /// <summary>
    /// 调用bat删除文件,以防止系统底层的异步删除机制
    /// </summary>
    /// <param name="filePath"></param>
    private static bool DeleteDirectoryWithCmd(string filePath)
    {
        var p = new Process();
        var info = new ProcessStartInfo("CMD.EXE", "/C del /F /S /Q \"" + filePath + "\"")
        {
            UseShellExecute = false,
            RedirectStandardOutput = true,
        };
        p.StartInfo = info;
        p.Start();
        p.WaitForExit();
        var output = p.StandardOutput.ReadToEnd();
        if (output.Contains(filePath))
        {
            return true;
        }
        return false;
    }


    /// <summary>
    /// 创建 zip 存档,该存档包含指定目录的文件和目录。
    /// </summary>
    /// <param name="srcDir">要存档的目录</param>
    /// <param name="dstFileName">要生成的存档</param>
    /// <param name="compressionLevel">压缩级别</param>
    /// <returns></returns>
    public static bool CreateZipFileFromDictionary(Dictionary<string, string> srcDir, string dstFileName, CompressionLevel compressionLevel = CompressionLevel.Fastest)
    {
        try
        {
            using (FileStream fs = new FileStream(dstFileName, FileMode.OpenOrCreate))
            {
                using (ZipArchive archive = new ZipArchive(fs, ZipArchiveMode.Update))
                {
                    foreach (var key in srcDir.Keys)
                    {
                        if (key != dstFileName)
                        {
                            var fileName = Path.GetFileName(key);
                            var entryList = new List<ZipArchiveEntry>();
                            foreach (var entry in archive.Entries)
                            {
                                if (fileName != null && (entry.FullName.StartsWith(fileName) || fileName.StartsWith(entry.FullName)))
                                {
                                    entryList.Add(entry);
                                }
                            }
                            entryList.ForEach(x => x.Delete());
                            archive.CreateEntryFromFile(key, srcDir[key], compressionLevel);
                        }
                    }
                }
            }
            return true;
        }
        catch (Exception ex)
        {
            string er = ex.Message;
            return false;
        }
    }
    /// <summary>
    /// 递归拷贝文件夹目录及文件
    /// </summary>
    /// <param name="srcDir"></param>
    /// <param name="dstDir"></param>
    /// <param name="bOverwrite">默认覆盖拷贝</param>
    /// <returns></returns>
    public static bool CopyDirectory(string srcDir, string dstDir, bool bOverwrite = true)
    {
        bool rslt = false;
        try
        {
            srcDir = srcDir.EndsWith(@"\") ? srcDir : srcDir + @"\";
            dstDir = dstDir.EndsWith(@"\") ? dstDir : dstDir + @"\";
            if (Directory.Exists(srcDir))
            {
                if (!Directory.Exists(dstDir))
                {
                    Directory.CreateDirectory(dstDir);
                }
                foreach (var item in Directory.GetFiles(srcDir))
                {
                    FileInfo fi = new FileInfo(item);
                    fi.CopyTo(dstDir + fi.Name, bOverwrite);
                }
                foreach (var dir in Directory.GetDirectories(srcDir))
                {
                    DirectoryInfo di = new DirectoryInfo(dir);
                    if (!CopyDirectory(dir, dstDir + di.Name, bOverwrite))
                    {
                        rslt = false;
                    }
                }
            }
            rslt = true;
        }
        catch (Exception ex)
        {
            string err = ex.Message;
            rslt = false;
        }
        return rslt;
    }
    /// <summary>
    ///  递归删除文件夹目录及文件
    /// </summary>
    /// <param name="baseDir"></param>
    /// <returns></returns>
    public static bool DeleteFolder(string baseDir)
    {
        var bRslt = true;
        try
        {
            if (Directory.Exists(baseDir))
            {
                foreach (var dir in Directory.GetFileSystemEntries(baseDir))
                {
                    if (File.Exists(dir))
                    {
                        File.Delete(dir);
                    }
                    else
                    {
                        bRslt = DeleteFolder(dir);
                    }
                }
                Directory.Delete(baseDir);
            }
        }
        catch (Exception ex)
        {
            string er = ex.Message;
            return false;
        }
        return bRslt;
    }

    #region extend

    public static void CreateEntryFromAny(this ZipArchive archive, string srcName, string entryName = "")
    {
        var fileName = Path.GetFileName(srcName);
        if (File.GetAttributes(srcName).HasFlag(FileAttributes.Directory))
        {
            archive.CreateEntryFromDirectory(srcName, Path.Combine(entryName, fileName));
        }
        else
        {
            archive.CreateEntryFromFile(srcName, Path.Combine(entryName, fileName), CompressionLevel.Fastest);
        }
    }
    public static void CreateEntryFromDirectory(this ZipArchive archive, string srcDirName, string entrName = "")
    {
        string[] files = Directory.GetFiles(srcDirName).Concat(Directory.GetDirectories(srcDirName)).ToArray();
        archive.CreateEntry(Path.Combine(entrName, Path.GetFileName(srcDirName)));
        foreach (var item in files)
        {
            archive.CreateEntryFromAny(item, entrName);
        }
    }
    #endregion

}
posted @ 2020-01-06 11:58  wesson2019  阅读(814)  评论(0)    收藏  举报