gzipstream定位.Net 3.5我遇到了麻烦的问题.这是我第一次使用gzipstream,但是我已经模拟了很多教程,包括这里,我仍然卡住了.
我的应用程序将数据表序列化为xml并插入数据库,将压缩数据存储到varbinary(max)字段以及未压缩缓冲区的原始长度.然后,当我需要它时,我检索这些数据并解压缩并重新创建数据表.解压缩似乎失败了.
编辑:遗憾的是,按照建议将GetBuffer更改为ToArray后,我的问题仍然存在.代码更新如下
压缩代码:
DataTable dt = new DataTable("MyUnit"); //do stuff with dt //okay... now compress the table using (MemoryStream xmlstream = new MemoryStream()) { //instead of stream, use xmlwriter? System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings(); settings.Encoding = Encoding.GetEncoding(1252); settings.Indent = false; System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(xmlstream, settings); try { dt.WriteXml(writer); writer.Flush(); } catch (ArgumentException) { //likely an encoding issue... okay, base64 encode it var base64 = Convert.ToBase64String(xmlstream.ToArray()); xmlstream.Write(Encoding.GetEncoding(1252).GetBytes(base64), 0, Encoding.GetEncoding(1252).GetBytes(base64).Length); } using (MemoryStream zipstream = new MemoryStream()) { GZipStream zip = new GZipStream(zipstream, CompressionMode.Compress); log.DebugFormat("Compressing commands..."); zip.Write(xmlstream.GetBuffer(), 0, xmlstream.ToArray().Length); zip.Flush(); float ratio = (float)zipstream.ToArray().Length / (float)xmlstream.ToArray().Length; log.InfoFormat("Resulting compressed size is {0:P2} of original", ratio); using (SqlCommand cmd = new SqlCommand()) { cmd.CommandText = "INSERT INTO tinydup (lastid, command, compressedlength) VALUES (@lastid,@compressed,@length)"; cmd.Connection = db; cmd.Parameters.Add("@lastid", SqlDbType.Int).Value = lastid; cmd.Parameters.Add("@compressed", SqlDbType.VarBinary).Value = zipstream.ToArray(); cmd.Parameters.Add("@length", SqlDbType.Int).Value = xmlstream.ToArray().Length; cmd.ExecuteNonQuery(); } }
解压缩代码:
/* This is an encapsulation of what I get from the database public class DupUnit{ public uint lastid; public uint complength; public byte[] compressed; }*/ //I have already retrieved my list of work to do from the database in a Listdupunits foreach (DupUnit unit in dupunits) { DataSet ds = new DataSet(); //DataTable dt = new DataTable(); //uncompress and extract to original datatable try { using (MemoryStream zipstream = new MemoryStream(unit.compressed)) { GZipStream zip = new GZipStream(zipstream, CompressionMode.Decompress); byte[] xmlbits = new byte[unit.complength]; //WHY ARE YOU ALWAYS 0!!!!!!!! int bytesdecompressed = zip.Read(xmlbits, 0, unit.compressed.Length); MemoryStream xmlstream = new MemoryStream(xmlbits); log.DebugFormat("Uncompressed XML against {0} is: {1}", m_source.DSN, Encoding.GetEncoding(1252).GetString(xmlstream.ToArray())); try{ ds.ReadXml(xmlstream); }catch(Exception) { //it may have been base64 encoded... decode first. ds.ReadXml(Encoding.GetEncoding(1254).GetString( Convert.FromBase64String( Encoding.GetEncoding(1254).GetString(xmlstream.ToArray()))) ); } xmlstream.Dispose(); } } catch (Exception e) { log.Error(e); Thread.Sleep(1000);//sleep a sec! continue; }
注意上面的注释... bytesdecompressed总是0.任何想法?我做错了吗?
编辑2:
所以这很奇怪.我将以下调试代码添加到解压缩例程中:
GZipStream zip = new GZipStream(zipstream, CompressionMode.Decompress); byte[] xmlbits = new byte[unit.complength]; int offset = 0; while (zip.CanRead && offset < xmlbits.Length) { while (zip.Read(xmlbits, offset, 1) == 0) ; offset++; }
在调试时,有时候循环会完成,但有时它会挂起.当我停止调试时,它将在1616年的第1600字节.我会继续,但它根本不会移动.
编辑3:该错误似乎在压缩代码中.无论出于何种原因,它都没有保存所有数据.当我尝试使用第三方gzip机制解压缩数据时,我只获得原始数据的一部分.
我会开始赏金,但到目前为止,我真的没有太多的声誉:-(
终于找到了答案.压缩数据不完整,因为GZipStream.Flush()完全没有确保所有数据都在缓冲区之外 - 您需要使用GZipStream.Close(),如此处所指出的那样.当然,如果你得到一个糟糕的压缩,它都会走下坡路 - 如果你尝试解压缩它,你将总是从Read()返回0.