从.Net 4.5开始的项目中,我们可以在引入 System.IO.Compression 和 System.IO.Compression.FileSystem (使用静态类ZipFile必需引入) 程序集的情况用以下静态方法很容易实现对整个目录的压缩:
ZipFile.CreateFromDirectory //注意需引入 System.IO.Compression.FileSystem 程序集
对于 .Net 4.5 之前的项目,压缩文件一般使用 SharpZipLib、DotNetZip等第三方压缩类库,但SharpZipLib貌似没有直接提供直接压缩目录的方法,但实际上在加入压缩文件的时候为文件指定存放到压缩文档中的入口位置(以目录层级方式表示)同样可以达到压缩整级目录的目的(DotNetZip貌似有提供,本文最后也会给出参考例子及出处,该方式未作实践)。
public class Zip
{
///
/// 创建压缩对象
///
/// 目标文件
///
public static ZipOutputStream CreateZip(string targeFile)
{
Directory.CreateDirectory(Path.GetDirectoryName(targeFile));
var s = new ZipOutputStream(File.Create(targeFile));
s.SetLevel(6);
return s;
}
///
/// 关闭压缩对象
///
///
public static void CloseZip(ZipOutputStream zip)
{
zip.Finish();
zip.Close();
}
///
/// 压缩文件,同时生成压缩文档内的层级目录
///
/// 压缩文件流
/// 不可空,待压缩的文件
/// 可空,压缩文件夹中目标位置(比如:“folder1\subfolder1\sub_subfolder1_1”,目录层级经过的目录在压缩文档中不存在都会生成,空则直接放压缩文件夹根位置)
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;
}
///
/// 解压缩
///
/// 压缩文档源文件
/// 解压后的目标文件夹路经
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>();
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 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博客