用SharpZipLib实现整个目录压缩(i.e: 在压缩文件中生成存放目录)【从.Net4.5开始用自带的ZipFile.CreateFromDirectory即可轻松实现】

从.Net 4.5开始的项目中,我们可以在引入 System.IO.Compression 和 System.IO.Compression.FileSystem (使用静态类ZipFile必需引入) 程序集的情况用以下静态方法很容易实现对整个目录的压缩:

ZipFile.CreateFromDirectory   //注意需引入 System.IO.Compression.FileSystem 程序集

对于 .Net 4.5 之前的项目,压缩文件一般使用 SharpZipLib、DotNetZip等第三方压缩类库,但SharpZipLib貌似没有直接提供直接压缩目录的方法,但实际上在加入压缩文件的时候为文件指定存放到压缩文档中的入口位置(以目录层级方式表示)同样可以达到压缩整级目录的目的(DotNetZip貌似有提供,本文最后也会给出参考例子及出处,该方式未作实践)。

一、以下是基于SharpZipLib实现文件生成压缩文档内的层级目录的方法的完整类代码:

public class Zip
{
    /// <summary>
    /// 创建压缩对象
    /// </summary>
    /// <param name="targeFile">目标文件</param>
    /// <returns></returns>
    public static ZipOutputStream CreateZip(string targeFile)
    {
        Directory.CreateDirectory(Path.GetDirectoryName(targeFile));
        var s = new ZipOutputStream(File.Create(targeFile));
        s.SetLevel(6);
        return s;
    }

    /// <summary>
    /// 关闭压缩对象
    /// </summary>
    /// <param name="zip"></param>
    public static void CloseZip(ZipOutputStream zip)
    {
        zip.Finish();
        zip.Close();
    }

    /// <summary>
    /// 压缩文件,同时生成压缩文档内的层级目录
    /// </summary>
    /// <param name="s">压缩文件流</param>
    /// <param name="sourceFile">不可空,待压缩的文件</param>
    /// <param name="zipIncludedFolder">可空,压缩文件夹中目标位置(比如:“folder1\subfolder1\sub_subfolder1_1”,目录层级经过的目录在压缩文档中不存在都会生成,空则直接放压缩文件夹根位置)</param>
    public static bool Compress(ZipOutputStream s, string sourceFile, string zipIncludedFolder)
    {
        if (s == null)
        {
            throw new FileNotFoundException("压缩文件流不可为空");
        }
        if (!File.Exists(sourceFile))
        {
            throw new FileNotFoundException(string.Format("未能找到文件 '{0}' ", sourceFile));
        }
        using (FileStream fs = File.OpenRead(sourceFile))
        {
            ZipEntry entry = null;
            if (string.IsNullOrWhiteSpace(zipIncludedFolder))
            {                    
                entry = new ZipEntry(Path.GetFileName(sourceFile));
            }
            else
            {                    
                entry = new ZipEntry(Path.Combine(zipIncludedFolder, Path.GetFileName(sourceFile)));
            }
            var buffer = File.ReadAllBytes(sourceFile);
            entry.DateTime = DateTime.Now;
            s.PutNextEntry(entry);
            s.Write(buffer, 0, buffer.Length);
        }
        return true;
    }

    /// <summary>
    /// 解压缩
    /// </summary>
    /// <param name="sourceFile">压缩文档源文件</param>
    /// <param name="targetPath">解压后的目标文件夹路经</param>
    public static bool Decompress(string sourceFile, string targetPath)
    {
        if (!File.Exists(sourceFile))
        {
            throw new FileNotFoundException(string.Format("未能找到文件 '{0}' ", sourceFile));
        }
        if (!Directory.Exists(targetPath))
        {
            Directory.CreateDirectory(targetPath);
        }
        using (ZipInputStream s = new ZipInputStream(File.OpenRead(sourceFile)))
        {
            ZipEntry theEntry;
            while ((theEntry = s.GetNextEntry()) != null)
            {
                string directorName = Path.Combine(targetPath, Path.GetDirectoryName(theEntry.Name));
                string fileName = Path.Combine(directorName, Path.GetFileName(theEntry.Name));
                if (directorName.Length > 0)
                {
                    Directory.CreateDirectory(directorName);
                }
                if (!string.IsNullOrWhiteSpace(fileName))
                {
                    using (FileStream streamWriter = File.Create(fileName))
                    {
                        int size = (int)theEntry.Size;
                        byte[] data = new byte[size];
                        size = s.Read(data, 0, data.Length);
                        if (size > 0)
                        {
                            streamWriter.Write(data, 0, size);
                        }
                    }
                }
            }
        }
        return true;
    }
}

二、使用以上类实现压缩整个目录的方法:

public void Example()
{
    var zipFile = @"D:\temp\ZipStore\testZipFileName.zip";
    var zipStream = Zip.CreateZip(zipFile);

    //测试“源目录文件”及“要存放到压缩包中的层级目录位置”:
    var filesToZip = new List<Tuple<string, string>>();
    var file1 = @"D:\temp\ZipTest\体检\TestSub\附件5:家属体检信息表.xlsx";
    var pathInZip1 = @"体检\TestSub";            
    filesToZip.Add(Tuple.Create(file1, pathInZip1));
    var file2 = @"D:\temp\ZipTest\体检\TestSub\1111\附件5:家属体检信息表.xlsx";
    var pathInZip2 = @"体检\TestSub\1111";
    filesToZip.Add(Tuple.Create(file2, pathInZip2));
    var file3 = @"D:\temp\ZipTest\体检2\TestSub\1111\TestSub\sfssfs.txt";
    var pathInZip3 = @"体检2\TestSub\1111\TestSub";
    filesToZip.Add(Tuple.Create(file3, pathInZip3));

    /*
     * 以上只是为了直观看效果,
     * 实际中应该使用以下方法获取要添加到压缩包的源目录下所有文件:
     * Directory.GetFiles(entireFolderPath, "*.*", SearchOption.AllDirectories) 
     * 并为所有文件根据文件路径用以下方法匹配出文件要存放到压缩包中的层级目录位置:
     * Path.GetDirectoryName("<去掉源文件夹位置前缀,对应压缩包中从层级目录开始的文件路径>")
     */

    filesToZip.ForEach(tupFileInfo =>
    {                
        Zip.Compress(zipStream, tupFileInfo.Item1, tupFileInfo.Item2);
    });

    zipStream.Close();            
}

测试效果如下图:

附:  DotNetZip 压缩文件夹方法(未做实践验证):

引入 DotNetZip DLL 并参考以下代码:

string[] MainDirs = Directory.GetDirectories(""c:\users\public\reports");

for (int i = 0; i < MainDirs.Length; i++)
{
    using (ZipFile zip = new ZipFile())
    {
        zip.UseUnicodeAsNecessary = true;
        zip.AddDirectory(MainDirs[i]);
        zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
        zip.Comment = "This zip was created at " + System.DateTime.Now.ToString("G");
        zip.Save(string.Format("test{0}.zip", i));   
    }
}

参考资料:

1. SharpZipLib 压缩文件夹:

https://www.zhankr.net/40888.html

2. DotNetZip 压缩文件夹 (
DotNetZip 源码:https://github.com/haf/DotNetZip.Semverd
):

https://www.coder.work/article/1652646 
(译自: https://stackoverflow.com/questions/20451073/zip-complete-folder-using-system-io-compression)

 但该出处中说的 “System.IO.Compression不能压缩一个完整的文件夹” 的说法在当下是不对的,如本文开头所提及的,在.Net 4.5之后自带了 System.IO.Compression 程序集,只需同时再引入 System.IO.Compression.FileSystem 程序集,即可轻松实现对整个目录的压缩打包。

【另一篇相关文章】:C#实现压缩与解压缩方案_c# 解压缩-CSDN博客

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值