压缩/解压缩string与C#
我在.net新手。 我正在做C#中的压缩和解压string。 有一个XML,我正在转换的string,之后,我正在做压缩和解压缩。除了当我解压缩我的代码并返回我的string,其返回只有一半的XML,我的代码没有编译错误。
下面是我的代码,请纠正我错在哪里。
码:
class Program { public static string Zip(string value) { //Transform string into byte[] byte[] byteArray = new byte[value.Length]; int indexBA = 0; foreach (char item in value.ToCharArray()) { byteArray[indexBA++] = (byte)item; } //Prepare for compress System.IO.MemoryStream ms = new System.IO.MemoryStream(); System.IO.Compression.GZipStream sw = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress); //Compress sw.Write(byteArray, 0, byteArray.Length); //Close, DO NOT FLUSH cause bytes will go missing... sw.Close(); //Transform byte[] zip data to string byteArray = ms.ToArray(); System.Text.StringBuilder sB = new System.Text.StringBuilder(byteArray.Length); foreach (byte item in byteArray) { sB.Append((char)item); } ms.Close(); sw.Dispose(); ms.Dispose(); return sB.ToString(); } public static string UnZip(string value) { //Transform string into byte[] byte[] byteArray = new byte[value.Length]; int indexBA = 0; foreach (char item in value.ToCharArray()) { byteArray[indexBA++] = (byte)item; } //Prepare for decompress System.IO.MemoryStream ms = new System.IO.MemoryStream(byteArray); System.IO.Compression.GZipStream sr = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress); //Reset variable to collect uncompressed result byteArray = new byte[byteArray.Length]; //Decompress int rByte = sr.Read(byteArray, 0, byteArray.Length); //Transform byte[] unzip data to string System.Text.StringBuilder sB = new System.Text.StringBuilder(rByte); //Read the number of bytes GZipStream red and do not a for each bytes in //resultByteArray; for (int i = 0; i < rByte; i++) { sB.Append((char)byteArray[i]); } sr.Close(); ms.Close(); sr.Dispose(); ms.Dispose(); return sB.ToString(); } static void Main(string[] args) { XDocument doc = XDocument.Load(@"D:\RSP.xml"); string val = doc.ToString(SaveOptions.DisableFormatting); val = Zip(val); val = UnZip(val); } }
我的XML大小是63KB。
压缩/解压缩string的代码
public static void CopyTo(Stream src, Stream dest) { byte[] bytes = new byte[4096]; int cnt; while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0) { dest.Write(bytes, 0, cnt); } } public static byte[] Zip(string str) { var bytes = Encoding.UTF8.GetBytes(str); using (var msi = new MemoryStream(bytes)) using (var mso = new MemoryStream()) { using (var gs = new GZipStream(mso, CompressionMode.Compress)) { //msi.CopyTo(gs); CopyTo(msi, gs); } return mso.ToArray(); } } public static string Unzip(byte[] bytes) { using (var msi = new MemoryStream(bytes)) using (var mso = new MemoryStream()) { using (var gs = new GZipStream(msi, CompressionMode.Decompress)) { //gs.CopyTo(mso); CopyTo(gs, mso); } return Encoding.UTF8.GetString(mso.ToArray()); } } static void Main(string[] args) { byte[] r1 = Zip("StringStringStringStringStringStringStringStringStringStringStringStringStringString"); string r2 = Unzip(r1); }
请记住, Zip
返回一个byte[]
,而Unzip
返回一个string
。 如果你想从Zip
一个string,你可以使用Base64对它进行编码(例如使用Convert.ToBase64String(r1)
)( Zip
的结果是非常的二进制的!你不能直接在屏幕上打印或直接写入XML )
build议的版本是.NET 2.0,.NET 4.0使用MemoryStream.CopyTo
。
重要:压缩的内容不能被写入输出stream,直到GZipStream
知道它具有所有的input(即有效地压缩它需要所有的数据)。 在检查输出stream(例如, mso.ToArray()
)之前,您需要确保已经Dispose()
了GZipStream
Dispose()
)。 这是用上面的using() { }
块完成的。 请注意, GZipStream
是最内层的块,内容在其外部访问。 在尝试访问数据之前,对GZipStream
进行解压缩也是一样的: Dispose()
。
根据这个片段我使用这个代码,它工作正常:
using System; using System.IO; using System.IO.Compression; using System.Text; namespace CompressString { internal static class StringCompressor { /// <summary> /// Compresses the string. /// </summary> /// <param name="text">The text.</param> /// <returns></returns> public static string CompressString(string text) { byte[] buffer = Encoding.UTF8.GetBytes(text); var memoryStream = new MemoryStream(); using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true)) { gZipStream.Write(buffer, 0, buffer.Length); } memoryStream.Position = 0; var compressedData = new byte[memoryStream.Length]; memoryStream.Read(compressedData, 0, compressedData.Length); var gZipBuffer = new byte[compressedData.Length + 4]; Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length); Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4); return Convert.ToBase64String(gZipBuffer); } /// <summary> /// Decompresses the string. /// </summary> /// <param name="compressedText">The compressed text.</param> /// <returns></returns> public static string DecompressString(string compressedText) { byte[] gZipBuffer = Convert.FromBase64String(compressedText); using (var memoryStream = new MemoryStream()) { int dataLength = BitConverter.ToInt32(gZipBuffer, 0); memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4); var buffer = new byte[dataLength]; memoryStream.Position = 0; using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) { gZipStream.Read(buffer, 0, buffer.Length); } return Encoding.UTF8.GetString(buffer); } } } }
随着.NET 4.0(及更高版本)和Stream.CopyTo()方法的出现,我想我会发布更新的方法。
我也认为下面的版本作为一个自包含的类来将常规string压缩成Base64编码的string的一个明显的例子是有用的,反之亦然:
public static class StringCompression { /// <summary> /// Compresses a string and returns a deflate compressed, Base64 encoded string. /// </summary> /// <param name="uncompressedString">String to compress</param> public static string CompressString(string uncompressedString) { var compressedStream = new MemoryStream(); var uncompressedStream = new MemoryStream(Encoding.UTF8.GetBytes(uncompressedString)); using (var compressorStream = new DeflateStream(compressedStream, CompressionMode.Compress, true)) { uncompressedStream.CopyTo(compressorStream); } return Convert.ToBase64String(compressedStream.ToArray()); } /// <summary> /// Decompresses a deflate compressed, Base64 encoded string and returns an uncompressed string. /// </summary> /// <param name="compressedString">String to decompress.</param> public static string DecompressString(string compressedString) { var decompressedStream = new MemoryStream(); var compressedStream = new MemoryStream(Convert.FromBase64String(compressedString)); using (var decompressorStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) { decompressorStream.CopyTo(decompressedStream); } return Encoding.UTF8.GetString(decompressedStream.ToArray()); } }
这里有一个扩展String类的版本,所以你可以简单地将这个类添加到你的项目中,然后使用:
var unCompressedString = "Hello World!"; var compressedString = unCompressedString.Compress();
以机智:
public static class Extensions { /// <summary> /// Compresses a string and returns a deflate compressed, Base64 encoded string. /// </summary> /// <param name="uncompressedString">String to compress</param> public static string Compress(this string uncompressedString) { var compressedStream = new MemoryStream(); var uncompressedStream = new MemoryStream(Encoding.UTF8.GetBytes(uncompressedString)); using (var compressorStream = new DeflateStream(compressedStream, CompressionMode.Compress, true)) { uncompressedStream.CopyTo(compressorStream); } return Convert.ToBase64String(compressedStream.ToArray()); } /// <summary> /// Decompresses a deflate compressed, Base64 encoded string and returns an uncompressed string. /// </summary> /// <param name="compressedString">String to decompress.</param> public static string Decompress(this string compressedString) { var decompressedStream = new MemoryStream(); var compressedStream = new MemoryStream(Convert.FromBase64String(compressedString)); using (var decompressorStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) { decompressorStream.CopyTo(decompressedStream); } return Encoding.UTF8.GetString(decompressedStream.ToArray()); } }
对于那些仍然得到GZip头幻数的是不正确的。 确保你传入一个GZipstream。 错误 ,如果你的string使用PHP压缩,你需要做的事情如:
public static string decodeDecompress(string originalReceivedSrc) { byte[] bytes = Convert.FromBase64String(originalReceivedSrc); using (var mem = new MemoryStream()) { //the trick is here mem.Write(new byte[] { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 8); mem.Write(bytes, 0, bytes.Length); mem.Position = 0; using (var gzip = new GZipStream(mem, CompressionMode.Decompress)) using (var reader = new StreamReader(gzip)) { return reader.ReadToEnd(); } } }