命名空间
System.IO.Compression
中
包含了
数据
压缩
/解压相关的
类
。
1.DeflateStream类和GZipStream类
从 .NET Framework 4.5 开始,DeflateStream类使用 zlib 库进行压缩。 因此,它提供更好的压缩算法,在大多数情况下,压缩文件比.NET Framework的早期版本更小。
DeflateStream 类与GZipStream类使用相同的压缩算法,其压缩的数据都是gzip的文件格式。注意该算法并不仅仅用于压缩文件,可以压缩来自其他流的数据。
压缩文件
void CompressFile(string originalFileName,string compressedFileName)
{
using (FileStream infileStream = File.Open(originalFileName, FileMode.Open))
{
using (FileStream outfileStream = File.Create(compressedFileName))
{
using (var compressor =
new DeflateStream(outfileStream, CompressionMode.Compress))
infileStream.CopyTo(compressor);
}
}
}
对于内存中的数据,可以使用类似的操作,例如:
using System.IO.Compression;
MemoryStream ms_in=new MemoryStream();
MemoryStream ms_out=new MemoryStream();
//fill a MemoryStream with data from a exist file
FileStream fs = new FileStream("aaa", FileMode.Open);
fs.CopyTo(ms_in);
fs.Close();
ms_in.Position = 0;//goto start
DeflateStream compressor = new DeflateStream(ms_out, CompressionMode.Compress);
ms_in.CopyTo(compressor);
Console.WriteLine("input bytes: " + ms_in.Length);
Console.WriteLine("output bytes: " + ms_out.Length);
ms_in.Close();
ms_out.Close();
/*
input bytes: 71680
output bytes: 57344
*/
解压文件
void DecompressFile(string compFileName, string decompFileName)
{
using (FileStream infileStream = File.Open(compFileName, FileMode.Open))
{
using (FileStream outfileStream = File.Create(decompFileName))
{
using (var decompressor =
new DeflateStream(outfileStream, CompressionMode.Decompress))
decompressor.CopyTo(outfileStream);
}
}
}
区别:
Deflate
Stream
提供
了算法上
的
数据压缩
,
压缩
的
数据
无法
使用
其他
软件
打开
,
但是
GZipStream
写入扩展名为 .gz 的文件的压缩对象,可以使用许多常用的压缩工具进行解压缩
,
但是,此类本质上不提供向 zip 存档添加文件或从 zip 存档中提取文件的功能。
例如,以下是同一个文件,分别通过DeflateStream和GZipStream进行压缩后的结果:
首先,在Windows环境下,GZipStream压缩后的文件,可以通过winrar等解压软件打开和解压缩,但是使用DeflateStream的则不行。
查看原始
数据
能够发现更多细节:
DeflateStream压缩数据
GZipStream压缩后的数据
对比可以看到,前面多了10个字节,结尾也多了8个字节。开头的10个字节(本例中是1F 8B 08 00 00 00 00 00 00 0A)是gzip文件头,结尾的8个字节,又分为了2个部分,前面4字节(本例中是BD C5 B2 98)是CRC位,后面4字节(本例中是BD 01 00 00)是未压缩数据的字节大小,对应数据0x000001BD=445字节。
2.BrotliStream类
GZIP压缩方法很通用,但并不是唯一的选择,Brotli压缩是一个由Google开发的解决方案,它使用与GZIP压缩相同的核心基础技术:LZ77算法和霍夫曼编解码,并使用现代方法对其进行增强。命名空间下含有与BrotliStream类,使用 Brotli 数据格式规范提供用于压缩和解压缩流,其操作方式与DeflateStream类和GZipStream类类似,主要是压缩和解压缩算法不同。
3.ZipFile类,ZipArchive类和ZipArchiveEntry类
该类提供创建、解压缩和打开 zip 存档的静态方法。CreateFromDirectory从目录创建 zip 存档,ExtractToDirectory方法分别从 zip 存档的内容提取到目录。
例如:
例如:
using System.IO.Compression;
ZipFile.CreateFromDirectory(@"F:\leet", @".\myzipfile.zip");
ZipFile.ExtractToDirectory(@".\myzipfile.zip", @".\extractDir");
但是
对于
通过
单个文件
创建
Zip
文档
,
则
无法
使用
上述
方法
,
具体
实现
方法
后面
将会
介绍
到
。
3.1.Zip存档文件中文件的检索
检索Zip存档文件中存在的文件,可以使用ZipArchive类和ZipArchiveEntry类,使用ZipArchive实例的Entries熟悉可以获取ZipArchiveEntry对象的集合:
ZipArchive zip = ZipFile.OpenRead("myzipfile.zip");
foreach (var ent in zip.Entries)
Console.WriteLine(ent.FullName);
注意
这种
方式
会
递归遍历
压缩文档
中
的
文件夹
,
即
如果
压缩文档
中
还有
文件夹
时
,
会
深入到
文件夹
中
去
遍历
。
也可以通过ZipArchive实例的GetEntry方法,以文件名的方式获取单个ZipArchiveEntry对象:
ZipArchive zip = ZipFile.OpenRead("myzipfile.zip");
ZipArchiveEntry? ent = zip.GetEntry("main.cpp");
if(ent != null)
Console.WriteLine(ent.FullName);
3.2.向Zip存档追加文件
还可以通过ZipArchive实例的CreateEntry添加新文件到Zip文档中,但是这个时候需要注意,Zip文档的打开方式应该是Open(而不是OpenRead):
using (ZipArchive zip = ZipFile.Open("myzipfile.zip",ZipArchiveMode.Update))
{
//Readme.txt是一个不存在的文件
ZipArchiveEntry readmeEntry = zip.CreateEntry("Readme.txt");
using (StreamWriter writer = new StreamWriter(readmeEntry.Open()))
{
writer.WriteLine("Information about this package.");
}
}
也可以
通过
现有
的
文件,直接
添加
添加到
Zip
文档
中
:
using (ZipArchive zip = ZipFile.Open("myzipfile.zip",ZipArchiveMode.Update))
{
//alreadyfile.c必须已存在
ZipArchiveEntry readmeEntry =
zip.CreateEntryFromFile("alreadyfile.c","addedfile.c");
}
上面
两种
方式
,
无论
那种
情况
,
如果
Zip
文档
中
已经
有
该
文件
,
则
会
导致
Zip
文档
中
会有
多个
同名
压缩
文件
。
如图
所示
:
所以
最好
是
在
添加
之前
检测
一下
是否
存在
同名
文件
。
3.3.从Zip存档提取文件
将Zip文档中的某个文档解压缩出来,可以使用ZipArchiveEntry的ExtractToFile方法:
ZipArchive zip = ZipFile.OpenRead("myzipfile.zip");
ZipArchiveEntry? ent = zip.GetEntry("main.cpp");
if(ent != null)
ent.ExtractToFile("main.cpp");//解压到文件
3.4.从Zip文档中删除文件
使用ZipArchiveEntry的Delete方法,例如:
string fileName = "myzipfile.zip";
using (ZipArchive zip = ZipFile.Open(fileName, ZipArchiveMode.Update))
{
ZipArchiveEntry? ent = zip.GetEntry("readme.txt");
if(ent!=null)
ent.Delete();
}
3.5.创建单一文件的Zip文档
回到前面的问题:如何创建仅包含一个新的压缩文件?可以通过向空的Zip文件中添加文件的方式,创建仅包含一个文件的压缩文件,如下所示:
string fileName = "solefile.zip";//该压缩文档不存在
using (ZipArchive zip = ZipFile.Open(fileName, ZipArchiveMode.Create))
{
zip.CreateEntryFromFile("readme.txt", "readme.txt");
}
4. 总结
以上基本可以覆盖大部分场景下的数据压缩也解压缩的应用了。