C#数据及文件的压缩和解压

命名空间 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 存档中提取文件的功能。

例如以下同一个文件分别通过DeflateStreamGZipStream进行压缩结果

首先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. 总结

以上基本可以覆盖大部分场景下的数据压缩也解压缩的应用了。

  • 30
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于大文件的流式压缩和加解密,我可以给你一些思路和建议: 1. 压缩:可以使用压缩算法如GZIP、ZIP等对大文件进行流式压缩。在C#中,可以使用System.IO.Compression命名空间提供的GZipStream和ZipArchive类来实现。 示例代码: ```csharp using (var sourceStream = File.OpenRead(sourceFilePath)) { using (var targetStream = File.Create(targetFilePath)) { using (var gzipStream = new GZipStream(targetStream, CompressionMode.Compress)) { sourceStream.CopyTo(gzipStream); } } } ``` 2. 解压:对于经过压缩的大文件,同样可以使用GZipStream或ZipArchive类进行流式解压缩。 示例代码: ```csharp using (var sourceStream = File.OpenRead(sourceFilePath)) { using (var targetStream = File.Create(targetFilePath)) { using (var gzipStream = new GZipStream(sourceStream, CompressionMode.Decompress)) { gzipStream.CopyTo(targetStream); } } } ``` 3. 加密:对于大文件的加密,可以使用加密算法如AES、DES等对大文件进行分块加密,以保证加密效率和安全性。在C#中,可以使用System.Security.Cryptography命名空间提供的加密类来实现。 示例代码: ```csharp using (var sourceStream = File.OpenRead(sourceFilePath)) { using (var targetStream = File.Create(targetFilePath)) { using (var aes = Aes.Create()) { // 设置加密密钥和向量 aes.Key = key; aes.IV = iv; // 创建加密流 using (var encryptor = aes.CreateEncryptor()) { using (var cryptoStream = new CryptoStream(targetStream, encryptor, CryptoStreamMode.Write)) { sourceStream.CopyTo(cryptoStream); } } } } } ``` 4. 解密:对于经过加密的大文件,同样可以使用加密类进行分块解密。 示例代码: ```csharp using (var sourceStream = File.OpenRead(sourceFilePath)) { using (var targetStream = File.Create(targetFilePath)) { using (var aes = Aes.Create()) { // 设置解密密钥和向量 aes.Key = key; aes.IV = iv; // 创建解密流 using (var decryptor = aes.CreateDecryptor()) { using (var cryptoStream = new CryptoStream(sourceStream, decryptor, CryptoStreamMode.Read)) { cryptoStream.CopyTo(targetStream); } } } } } ``` 需要注意的是,在进行大文件的流式处理时,应该尽量避免将整个文件读取到内存中,而是采用分块读取的方式,以减少内存占用和提高处理效率。同时,在进行加解密操作时,应该谨慎处理加密密钥和向量,以保证数据的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值