SharpZipLib压缩字符串
本文关键字:字符串 压缩 SharpZipLib | 更新日期: 2023-09-27 18:28:38
我需要压缩一个字符串来减少web服务响应的大小。我在SharpZipLib样本中看到了单元测试,但并不是我所需要的示例。
在以下代码中,ZipOutputStream的构造函数返回异常:"No open entry"
byte[] buffer = Encoding.UTF8.GetBytes(SomeLargeString);
Debug.WriteLine(string.Format("Original byes of string: {0}", buffer.Length));
MemoryStream ms = new MemoryStream();
using (ZipOutputStream zipStream = new ZipOutputStream(ms))
{
zipStream.Write(buffer, 0, buffer.Length);
Debug.WriteLine(string.Format("Compressed byes: {0}", ms.Length));
}
ms.Position = 0;
MemoryStream outStream = new MemoryStream();
byte[] compressed = new byte[ms.Length];
ms.Read(compressed, 0, compressed.Length);
byte[] gzBuffer = new byte[compressed.Length + 4];
System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
string compressedString = Convert.ToBase64String (gzBuffer);
我从哪里偏离轨道的?我是不是让这件事变得更复杂了?
对于Silverlight中的web服务通信压缩数据,我使用以下代码段:
private byte[] zipText(string text)
{
if (text == null)
return null;
using(Stream memOutput = new MemoryStream())
{
using (GZipOutputStream zipOut = new GZipOutputStream(memOutput))
{
using (StreamWriter writer = new StreamWriter(zipOut))
{
writer.Write(text);
writer.Flush();
zipOut.Finish();
byte[] bytes = new byte[memOutput.Length];
memOutput.Seek(0, SeekOrigin.Begin);
memOutput.Read(bytes, 0, bytes.Length);
return bytes;
}
}
}
}
private string unzipText(byte[] bytes)
{
if (bytes == null)
return null;
using(Stream memInput = new MemoryStream(bytes))
using(GZipInputStream zipInput = new GZipInputStream(memInput))
using(StreamReader reader = new StreamReader(zipInput))
{
string text = reader.ReadToEnd();
return text;
}
}
- 我使用GZip而不是Zip压缩
- 预期文本将从类似的环境中读取/写入,所以我没有进行任何额外的编码/解码
我的案例是json数据的压缩。根据我的观察,在某些情况下,大约95Kb的文本数据被压缩到1.5Kb。因此,即使数据也会被序列化到64位,无论如何都可以很好地节省流量。
发布了我的答案,这可能是为了节省一些时间。
您确定将数据转换为Base64后数据会小得多吗?这将显著膨胀二进制数据(zip)。难道不能使用HTTP压缩在传输级别解决这个问题吗?
这里有一篇完整的文章,展示了如何进行往返的zip/unzip。
http://paultechguy.blogspot.com/2008/09/zip-xml-in-memory-for-web-service.html
代码中的一些问题:
-
使用流时始终刷新数据。
-
要从MemoryStream读取数据,只需使用:
byte[]数据=毫秒ToArray();
-
Zip文件是可能包含多个条目(文件)、注释。。。在开始向其写入数据之前,您可能需要调用PutNextEntry()来添加新条目。
-
如果你只需要压缩一个数据流(这是你的情况),你最好的选择是简单地使用deflate(或gzip)压缩,它意味着压缩单个数据流(实际上zip格式在内部使用gzip来压缩其条目…).Net为数据压缩提供了两个非常方便的类:GZipStream和DeflateStream。可以在这里找到一个好的样本
在写入数据之前,您需要调用PutNextEntry来添加头。
答案复制自:http://community.sharpdevelop.net/forums/p/5910/16947.aspx
我发现的最简单的答案是在解压缩/压缩数据时处理字节,并使用一个设置大小的缓冲区将数据复制到一个可以随意使用的Stream对象:
/// <summary>
/// Unzips (inflates) zipped data.
/// </summary>
/// <param name="zippedData">The zipped data.</param>
/// <returns>The inflated data.</returns>
public Byte[] GUnzip(Byte[] zippedData)
{
using (MemoryStream unzippedData = new MemoryStream())
{
using (GZipInputStream zippedDataStream = new GZipInputStream(new MemoryStream(zippedData)))
{
CopyStream(zippedDataStream, unzippedData);
}
return unzippedData.ToArray();
}
}
/// <summary>
/// zips data.
/// </summary>
/// <param name="unzippedData">The unzipped data.</param>
/// <returns>The zipped data.</returns>
public Byte[] GZip(Byte[] unzippedData)
{
using (MemoryStream zippedData = new MemoryStream())
{
using (GZipOutputStream unzippedDataStream = new GZipOutputStream(new MemoryStream(unzippedData)))
{
CopyStream(unzippedDataStream, zippedData);
}
return zippedData.ToArray();
}
}
/// <summary>
/// Accepts an inStream, writes it to a buffer and goes out the outStream
/// </summary>
/// <param name="inStream">The input Stream</param>
/// <param name="outStream">The output Stream</param>
private static void CopyStream(Stream inStream, Stream outStream)
{
int nRead = 0;
// Using a 2k buffer
Byte[] theBuffer = new Byte[2048];
while ((nRead = inStream.Read(theBuffer, 0, theBuffer.Length)) > 0)
{
outStream.Write(theBuffer, 0, nRead);
}
}