數據壓縮是一個軟件開發中的常見需求:很多時候需要先將較大的數據進行壓縮然后再通過網絡等進行傳輸。
在 .NET 中,有多個壓縮算法供我們選擇:Deflate、GZip 和 Br 。這些壓縮算法都是基于流(Stream)的,在對字符串壓縮前需要先將其轉換成字節數組。
還有一個比較常見的壓縮算法是:lz-string 。其官方文檔在這里:
https://pieroxy.net/blog/pages/lz-string/index.html
壓縮后的數據一般是流或者字節數組,在壓縮字符串的場景下,期望的壓縮結果大概率也是字符串。常見的字節數組編碼方式有以下幾種:
Base16
Base62
Base64
Ascii85
不同的壓縮算法對應了不同的解壓縮算法。同樣的,不同的編碼算法也對應了不同的解碼算法。為了降低使用難度,可以在壓縮結果中將使用的壓縮算法和編碼算法嵌入,這樣就可以使用一個解壓縮方法去解壓任意支持的數據。
LuYao.Common
基于上述考慮,筆者編寫了一個名為?StringZipper
?的靜態類用于輔助進行字符串的壓縮和解壓縮。該類屬于?LuYao.Common
?,可以在 NuGet 下載:
https://www.nuget.org/packages/LuYao.Common/
StringZipper 的成員
public static class StringZipper
{public interface ICompressor{string Identifier { get; }byte[] Compress(string value);string Decompress(byte[] data);}public interface IEncoder{string Identifier { get; }string Encode(byte[] data);byte[] Decode(string value);}public static IEncoder Base16 { get; }public static IEncoder Base62 { get; }public static IEncoder Base64 { get; }public static IEncoder Ascii85 { get; }public static ICompressor LzString { get; }public static ICompressor Deflate { get; }public static ICompressor GZip { get; }public static ICompressor Br { get; }private static void Register(string identifier, object component);public static void Register(ICompressor compresser);public static void Register(IEncoder encoder);public static bool TryGetComponent<T>(string id, out T component);public static string Zip(string str, ICompressor compressor, IEncoder encoder);public static string Zip(string str);public static string Unzip(string str);
}
使用 StringZipper 壓縮字符串
最簡單的使用方式就是直接調用?StringZipper
?的?Zip
?方法,默認情況下會使用 Deflate 壓縮算法和 Ascii85 編碼:
using LuYao;
var input = "man is distinguished, not only by his reason, but also by this singular passion from other animals; in whom the appetite of food, and other pleasures of sense, by predominance, take away the care of knowing causes; which is a lust of the mind, that by a perseverance of delight in the continual and indefatigable generation of knowledge, exceedeth the short vehemence of any carnal pleasure.";
var output = StringZipper.Zip(input);
Console.WriteLine(output);var bytesFrom = Encoding.UTF8.GetByteCount(input);
var bytesTo = Encoding.UTF8.GetByteCount(output);Console.WriteLine("{0} => {1} {2:0.##%}",bytesFrom,bytesTo,1d*bytesTo/bytesFrom);
輸出:
data:text/x-deflate;ascii85,<~23?4J`%VHa>G6S<CZ)39YnDE7!KY'd9D=2tfhW"J,^cgm0hTEta?GJmU_ekKWRQilMfOb<fMl1a$n&3T;ti;VBr]sfYusqtXm8:<)4amP&^.pgK[(QXW5PgSMh?,H9f94YdUQrJ@Rc-tTg9*LGZ!ctH5'dj6Z@JZjlBPEZuWoYDp^A@`-W=Fo#t[io.[%&/<8EOoq4^IBD)XDC?UB_qF&Z#KNe*9ZggakM-h-*mulYK`a3gp.VOTjcf`PKIRVtc+T>Ca_=NYjXPN,nMuui]b;FW>@)!NXquZ~>
391 => 320 81.84%
如果需要使用其他的壓縮算法或編碼方式,Zip
?方法有一個需要三個參數的重載,將對應的靜態屬性傳入即可。如果需要使用 Br 壓縮和 Base64 編碼,則可以使用以下代碼:
var output = StringZipper.Zip(input, StringZipper.Br,StringZipper.Base62);
使用 StringZipper 解壓字符串
與壓縮時可以指定壓縮和編碼方式相比,解壓縮只有一個方法:?Unzip
?。該方法會自動判斷傳入的字符串是否被壓縮以及壓縮時使用的參數:
using LuYao;
var input = "data:text/x-deflate;ascii85,<~23?4J`%VHa>G6S<CZ)39YnDE7!KY'd9D=2tfhW\"J,^cgm0hTEta?GJmU_ekKWRQilMfOb<fMl1a$n&3T;ti;VBr]sfYusqtXm8:<)4amP&^.pgK[(QXW5PgSMh?,H9f94YdUQrJ@Rc-tTg9*LGZ!ctH5'dj6Z@JZjlBPEZuWoYDp^A@`-W=Fo#t[io.[%&/<8EOoq4^IBD)XDC?UB_qF&Z#KNe*9ZggakM-h-*mulYK`a3gp.VOTjcf`PKIRVtc+T>Ca_=NYjXPN,nMuui]b;FW>@)!NXquZ~>";
var output = StringZipper.Unzip(input);
Console.WriteLine(output);
輸出:
man is distinguished, not only by his reason, but also by this singular passion from other animals; in whom the appetite of food, and other pleasures of sense, by predominance, take away the care of knowing causes; which is a lust of the mind, that by a perseverance of delight in the continual and indefatigable generation of knowledge, exceedeth the short vehemence of any carnal pleasure.
路遙工具箱中的功能集成
路遙工具箱已經內置了【文本壓縮】功能,在【文字處理】菜單下。其采用的壓縮、解壓算法與本文所采用的相同。這就代表著可以在開發或者調試時很容易對已壓縮的數據進行解壓,提高軟件開發的效率。