C# 字符串压缩和解压
DebugUsery 人气:0利用GZip和Brotli压缩方法的优势,减少字符串数据的大小,提高.NET核心应用程序的性能。
在开发应用程序时,你经常需要处理字符串。由于字符串对象在性能方面的成本很高,你经常想压缩你的字符串内容,即字符串对象中的数据,以减少有效载荷。有几个库可以做到这一点,但两个流行的技术是GZip和Brotli。
在这篇文章中,我们将讨论如何在C#中使用GZip和Brotli算法对字符串进行压缩和解压。要使用这里提供的代码示例,你的系统中应该安装有Visual Studio 2022。如果你还没有副本,你可以在这里下载Visual Studio 2022。
在Visual Studio 2022中创建一个控制台应用程序项目
首先,让我们在Visual Studio中创建一个.NET Core控制台应用程序项目。假设你的系统中已经安装了Visual Studio 2022,按照下面的步骤创建一个新的.NET Core控制台应用程序项目:
- 启动Visual Studio IDE。
- 点击 "创建一个新项目"。
- 在 "创建一个新项目 "窗口中,从显示的模板列表中选择 "控制台应用程序"。
- 点击 "下一步"。
- 在接下来显示的 "配置你的新项目 "窗口中,指定新项目的名称和位置。
- 在 "其他信息 "窗口中,选择.NET 6.0作为运行时间,然后点击下一步。
- 点击 "创建"。
我们将使用这个项目来说明下面的字符串压缩和解压缩。但首先我们要安装一个基准测试包BenchmarkDotNet,它将使我们能够衡量我们从压缩中获得的好处。
安装BenchmarkDotNet NuGet包
基准测试代码对于了解你的应用程序的性能至关重要。在这篇文章中,我们将利用BenchmarkDotNet来跟踪方法的性能。
要使用BenchmarkDotNet,你必须安装BenchmarkDotNet软件包。你可以通过Visual Studio 2022里面的NuGet软件包管理器,或者在NuGet软件包管理器控制台执行以下命令来完成。
Install-Package BenchmarkDotNet
C#中的System.IO.Compression命名空间
System.IO.Compression命名空间包括压缩文件和字符串的方法。它包含两种压缩算法。GZip 和 Brotli。在接下来的章节中,我们将研究如何在C#中使用GZip和Brotli压缩算法对字符串数据进行压缩和解压。
我们将在下面的例子中使用以下文本。
string originalString = "To work with BenchmarkDotNet you must install the BenchmarkDotNet package. " + "You can do this either via the NuGet Package Manager inside the Visual Studio 2019 IDE, " + "or by executing the Install-Package BenchmarkDotNet command at the NuGet Package Manager Console";
在C#中使用GZip对数据进行压缩和解压
下面的代码片断显示了如何在C#中使用GZipStream类来压缩数据。注意,压缩方法的参数是一个字节数组:
public static byte[] Compress(byte[] bytes) { using (var memoryStream = new MemoryStream()) { using (var gzipStream = new GZipStream(memoryStream, CompressionLevel.Optimal)) { gzipStream.Write(bytes, 0, bytes.Length); } return memoryStream.ToArray(); } }
要解压使用GZip算法压缩过的数据,我们可以使用以下方法:
public static byte[] Decompress(byte[] bytes) { using (var memoryStream = new MemoryStream(bytes)) { using (var outputStream = new MemoryStream()) { using (var decompressStream = new GZipStream(memoryStream, CompressionMode.Decompress)) { decompressStream.CopyTo(outputStream); } return outputStream.ToArray(); } } }
运行GZip压缩算法
你可以使用下面的代码片断来执行我们刚刚创建的GZip压缩方法:
byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString); byte[] compressedData = GZipCompressor.Compress(dataToCompress); string compressedString = Encoding.UTF8.GetString(compressedData); Console.WriteLine("Length of compressed string: " + compressedString.Length); byte[] decompressedData = GZipCompressor.Decompress(compressedData); string deCompressedString = Encoding.UTF8.GetString(decompressedData); Console.WriteLine("Length of decompressed string: " + deCompressedString.Length);
当你运行上述代码时,你会在控制台窗口看到以下输出:
图1.GZip将原来259个字符的字符串压缩成167个字符。
请注意,GZip从原始的259个字符的字符串中修剪了92个字符。因为原始字符串和解压后的字符串应该是相同的,它们的长度也应该是相同的。
在C#中使用Brotli对数据进行压缩和解压
下面的代码片断说明了如何在C#中使用BrotliStream类来压缩数据。与上面的GZip例子一样,注意压缩方法的参数是一个字节数组:
public static byte[] Compress(byte[] bytes) { using (var memoryStream = new MemoryStream()) { using (var brotliStream = new BrotliStream(memoryStream, CompressionLevel.Optimal)) { brotliStream.Write(bytes, 0, bytes.Length); } return memoryStream.ToArray(); } }
而这里是你如何使用BrotliStream来解压数据的:
public static byte[] Decompress(byte[] bytes) { using (var memoryStream = new MemoryStream(bytes)) { using (var outputStream = new MemoryStream()) { using (var decompressStream = new BrotliStream(memoryStream, CompressionMode.Decompress)) { decompressStream.CopyTo(outputStream); } return outputStream.ToArray(); } } }
运行Brotli压缩算法
下面的代码片断显示了你如何使用我们上面创建的Brotli压缩方法来压缩一个字符串:
Console.WriteLine("Length of original string: " + originalString.Length); byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString); byte[] compressedData = BrotliCompressor.Compress(dataToCompress); string compressedString = Convert.ToBase64String(compressedData); Console.WriteLine("Length of compressed string: " + compressedString.Length); byte[] decompressedData = BrotliCompressor.Decompress(compressedData); string deCompressedString = Convert.ToBase64String(decompressedData); Console.WriteLine("Length of decompressed string: " + deCompressedString.Length);
当你运行该程序时,你将在控制台窗口看到以下输出:
图2.Brotli将原来259个字符的字符串压缩成121个字符。
正如你所看到的,Brotli的压缩效果比GZip好得多。然而,压缩率并不是故事的全部,我们将在下面看到。
用GZip和Brotli进行异步压缩和解压
请注意,我们之前使用的压缩和解压方法也有异步的对应方法。这里是使用GZip算法的压缩和解压方法的异步版本:
public async static Task<byte[]> CompressAsync(byte[] bytes) { using (var memoryStream = new MemoryStream()) { using (var gzipStream = new GZipStream(memoryStream, CompressionLevel.Optimal)) { await gzipStream.WriteAsync(bytes, 0, bytes.Length); } return memoryStream.ToArray(); } }
public async static Task<byte[]> DecompressAsync(byte[] bytes) { using (var memoryStream = new MemoryStream(bytes)) { using (var outputStream = new MemoryStream()) { using (var decompressStream = new GZipStream(memoryStream, CompressionMode.Decompress)) { await decompressStream.CopyToAsync(outputStream); } return outputStream.ToArray(); } } }
这里是使用Brotli的压缩和解压方法的异步版本:
public static async Task<byte[]> CompressAsync(byte[] bytes) { using (var memoryStream = new MemoryStream()) { using (var brotliStream = new BrotliStream(memoryStream, CompressionLevel.Optimal)) { await brotliStream.WriteAsync(bytes, 0, bytes.Length); } return memoryStream.ToArray(); } }
public static async Task<byte[]> DecompressAsync(byte[] bytes) { using (var memoryStream = new MemoryStream(bytes)) { using (var outputStream = new MemoryStream()) { using (var brotliStream = new BrotliStream(memoryStream, CompressionMode.Decompress)) { await brotliStream.CopyToAsync(outputStream); } return outputStream.ToArray(); } } }
在C#中用GZip和Brotli进行压缩和解压的基准测试
在我们之前创建的控制台应用程序项目中,创建一个名为BenchmarkCompression.cs的新文件并输入以下代码:
[MemoryDiagnoser] [Orderer(BenchmarkDotNet.Order.SummaryOrderPolicy.FastestToSlowest)] [RankColumn] public class BenchmarkCompression { string originalString = "To work with BenchmarkDotNet you must install the BenchmarkDotNet package. " + "You can do this either via the NuGet Package Manager inside the Visual Studio 2019 IDE, " + "or by executing the Install-Package BenchmarkDotNet command at the NuGet Package Manager Console"; [Benchmark] public void GZipCompress() { byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString); var compressedData = GZipCompressor.Compress(dataToCompress); } [Benchmark] public void BrotliCompress() { byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString); var compressedData = BrotliCompressor.Compress(dataToCompress); } }
当你运行基准时,你应该看到类似于下面图3所示的控制台输出。
图3.来自BenchmarkDotNet的结果...GZip赢了!
显然,在选择压缩算法时,压缩率并不是唯一的考虑因素。尽管与GZip相比,你可以使用Brotli实现更好的压缩,但额外的压缩是以性能为代价的。GZip在压缩和解压数据方面明显比Brotli快。
当对你的.NET应用程序进行基准测试时,你应该始终确保你的项目在发布模式下运行。原因是编译器为调试和发布模式优化代码的方式不同。关于基准测试和应用程序的性能,我在以后的文章中会有更多论述。
加载全部内容