向高手请教解压缩反序列化的问题
下面的fun()函数对data进行解压缩并反序列化void fun() {
byte[] data = getData();
byte[] data2 = myDecompress(data); //调用myDecompress函数解压缩
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream(data2);
object surrogate = bf.Deserialize(ms); //反序列化
}
(1)private byte[] myDecompress(byte[] data) //解压缩函数一,这段代码没问题
{
MemoryStream ms = new MemoryStream(data);
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress, true);
byte[] buffer = new byte[4096];
MemoryStream output = new MemoryStream();
int read = -1;
read = zipStream.Read(buffer, 0, buffer.Length);
while (read > 0)
{
output.Write(buffer, 0, read);
read = zipStream.Read(buffer, 0, buffer.Length);
}
zipStream.Close();
ms.Close();
return output.ToArray();
}
(2)private byte[] myDecompress2(byte[] data) //解压缩函数二,这段代码被调用后会产生异常
{
MemoryStream ms = new MemoryStream();
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress, true);
byte[] buffer = new byte[data.Length]; //如果数组data的长度太长,是不是这句写的不合理呢?
zipStream.Read(buffer, 0, data.Length);
return buffer;
}
本人觉得第2段代码直接返回buffer跟第一段的代码效果一样,但这样当调用fun()函数中的
object surrogate = bf.Deserialize(ms); 时会引发SerializationException异常:
End of Stream encountered before parsing was completed.
然后在函数myDecompress2中
byte[] buffer = new byte[data.Length]; //如果数组data的长度太长,是不是这句写的不合理呢?
请教各位,谢谢!
--------------------编程问答-------------------- (2)private byte[] myDecompress2(byte[] data) //解压缩函数二,这段代码被调用后会产生异常
{
MemoryStream ms = new MemoryStream();
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress, true);
byte[] buffer = new byte[data.Length]; //如果数组data的长度太长,是不是这句写的不合理呢?
zipStream.Read(buffer, 0, data.Length);
return buffer;
}
问题太大了把
MemoryStream ms = new MemoryStream(); //空~~
byte[] buffer = new byte[data.Length]; 解压后的大小不是这个
你返回了一个空~~然后去反序列化空~~ --------------------编程问答--------------------
--------------------编程问答-------------------- private byte[] myDecompress2(byte[] data) //解压缩函数二,这段代码被调用后会产生异常
2)private byte[] myDecompress2(byte[] data) //解压缩函数二,这段代码被调用后会产生异常
{
MemoryStream ms = new MemoryStream();
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress, true);
byte[] buffer = new byte[data.Length]; //如果数组data的长度太长,是不是这句写的不合理呢?
zipStream.Read(buffer, 0, data.Length);
return buffer.ToArray();
}
{
MemoryStream ms = new MemoryStream();
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress, true);
byte[] buffer = new byte[data.Length]; //如果数组data的长度太长,是不是这句写的不合理呢?
zipStream.Read(buffer, 0, data.Length);
return buffer.ToArray(); }
--------------------编程问答-------------------- 不要意思
把函数myDecompress2(byte[] data)里第一句更正如下:
MemoryStream ms = new MemoryStream(data); --------------------编程问答-------------------- 回3楼
没有buffer.ToArray()这个方法 --------------------编程问答--------------------
byte[] buffer 是一个数组,怎么会没有.ToArray()方法?你测试过了?
--------------------编程问答-------------------- 对呀
测试过了
没有这个方法 --------------------编程问答-------------------- 问题应该是处在buffer数组的长度上
buffer数组的长度定义应该是取解压缩后的字符流长度
byte[] buffer = new byte[data.Length];
==>
byte[] buffer = new byte[zipStream.Length];
--------------------编程问答-------------------- 读取的方法同样也要修改,希望能对你有所帮助 --------------------编程问答-------------------- 回楼上
我把方法改称这样子:
private byte[] myDecompress2(byte[] data) //解压缩函数二,这段代码被调用后会产生异常
{
MemoryStream ms = new MemoryStream();
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress, true);
byte[] buffer = new byte[zipStream.Length];
zipStream.Read(buffer, 0, Convert.ToInt32(zipStream.Length));
return buffer;
}
执行到此句byte[] buffer = new byte[zipStream.Length];时
抛出NotSupportedException
This operation is not supported. --------------------编程问答-------------------- 对于方法二抛出的异常更详细的信息如下:
<ExceptionType>System.Runtime.Serialization.SerializationException, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>Binary stream '0' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.</Message> --------------------编程问答-------------------- 下面给出测试代码(windows应用程序)
希望通过大家的努力能知道为什么!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
namespace DataSetApp11
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string connStr = @"server=WT-SH-GWZ172X\SQLEXPRESS;database=test;trusted_connection=true";
string sql = "select * from myUser";
DataSet ds = new DataSet();
using (SqlConnection conn = new SqlConnection(connStr))
{
using (SqlDataAdapter da = new SqlDataAdapter(sql, conn))
{
da.Fill(ds);
byte[] data = serializeAndCompressDataSet(ds);
//byte[] buffer = myDecompress2(data); //会产生异常
byte[] buffer = myDecompress(data); //没问题
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream(buffer);
DataSet ds2 = bf.Deserialize(ms) as DataSet;
ms.Close();
this.dataGridView1.DataSource = ds2.Tables[0];
}
}
}
private byte[] myDecompress2(byte[] data) //解压缩函数二,这段代码被调用后会产生异常
{
MemoryStream ms = new MemoryStream();
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress, true);
byte[] buffer = new byte[data.Length]; //如果数组data的长度太长,是不是这句写的不合理呢?
zipStream.Read(buffer, 0, Convert.ToInt32(data.Length));
return buffer;
}
private byte[] myDecompress(byte[] data) //解压缩函数一,这段代码没问题
{
MemoryStream ms = new MemoryStream(data);
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress, true);
byte[] buffer = new byte[4096];
MemoryStream output = new MemoryStream();
int read = -1;
read = zipStream.Read(buffer, 0, buffer.Length);
while (read > 0)
{
output.Write(buffer, 0, read);
read = zipStream.Read(buffer, 0, buffer.Length);
}
zipStream.Close();
ms.Close();
return output.ToArray();
}
private byte[] serializeAndCompressDataSet(DataSet ds) //序列化并压缩DataSet
{
MemoryStream ms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, ds);
byte[] data = ms.ToArray();
ms.Close();
MemoryStream output = new MemoryStream();
GZipStream zipStream = new GZipStream(output, CompressionMode.Compress, true);
zipStream.Write(data, 0, data.Length);
zipStream.Close();
output.Close();
return output.ToArray();
}
}
} --------------------编程问答-------------------- zipStream.Length
==》
zipStream.BaseStream.Length
原因就是buffer数组的长度定义应该是取解压缩后的字符流长度
--------------------编程问答-------------------- 另外
MemoryStream ms = new MemoryStream();
=>
MemoryStream ms = new MemoryStream(data);
这个上面有人已经说了 --------------------编程问答-------------------- 另外如果压缩的字符流比较长
zipStream.Read(buffer, 0, Convert.ToInt32(zipStream.BaseStream.Length));
直接转换成int并不合适,这里只是一个例子,你需要拆分为多个byte数组处理 --------------------编程问答-------------------- private byte[] myDecompress2(byte[] data)
{
MemoryStream ms = new MemoryStream(data);
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress, true);
byte[] buffer = new byte[zipStream.BaseStream.Length];
zipStream.Read(buffer, 0, Convert.ToInt32(zipStream.BaseStream.Length));
return buffer;
}
请问楼上 如果用这种方法是不是读一次就有了呢?
但上面的代码还是会有异常。
我检查了发现byte[] buffer = myDecompress(data);跟byte[] buffer = myDecompress2(data);
buffer的维数是不同的,myDecompress2的小 --------------------编程问答-------------------- zipStream.Read(buffer, 0, Convert.ToInt32(zipStream.BaseStream.Length));
要读多次的
因为Read方法的参数是Int,而byte数组的Length是long。可以把byte数组拆成N个长度为2048的数组,最后Contact就好 --------------------编程问答-------------------- 给你贴下完整的例子源代码吧
using System;
using System.IO;
using System.IO.Compression;
public class GZipTest
{
private const int buffer_size = 100;
public static int ReadAllBytesFromStream(Stream stream, byte[] buffer)
{
// Use this method is used to read all bytes from a stream.
int offset = 0;
int totalCount = 0;
while (true)
{
int bytesRead = stream.Read(buffer, offset, buffer_size);
if (bytesRead == 0)
{
break;
}
offset += bytesRead;
totalCount += bytesRead;
}
return totalCount;
}
public static bool CompareData(byte[] buf1, int len1, byte[] buf2, int len2)
{
// Use this method to compare data from two different buffers.
if (len1 != len2)
{
Console.WriteLine("Number of bytes in two buffer are different {0}:{1}", len1, len2);
return false;
}
for (int i = 0; i < len1; i++)
{
if (buf1[i] != buf2[i])
{
Console.WriteLine("byte {0} is different {1}|{2}", i, buf1[i], buf2[i]);
return false;
}
}
Console.WriteLine("All bytes compare.");
return true;
}
public static void GZipCompressDecompress(string filename)
{
Console.WriteLine("Test compression and decompression on file {0}", filename);
FileStream infile;
try
{
// Open the file as a FileStream object.
infile = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
byte[] buffer = new byte[infile.Length];
// Read the file to ensure it is readable.
int count = infile.Read(buffer, 0, buffer.Length);
if (count != buffer.Length)
{
infile.Close();
Console.WriteLine("Test Failed: Unable to read data from file");
return;
}
infile.Close();
MemoryStream ms = new MemoryStream();
// Use the newly created memory stream for the compressed data.
GZipStream compressedzipStream = new GZipStream(ms, CompressionMode.Compress, true);
Console.WriteLine("Compression");
compressedzipStream.Write(buffer, 0, buffer.Length);
// Close the stream.
compressedzipStream.Close();
Console.WriteLine("Original size: {0}, Compressed size: {1}", buffer.Length, ms.Length);
// Reset the memory stream position to begin decompression.
ms.Position = 0;
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress);
Console.WriteLine("Decompression");
byte[] decompressedBuffer = new byte[buffer.Length + buffer_size];
// Use the ReadAllBytesFromStream to read the stream.
int totalCount = GZipTest.ReadAllBytesFromStream(zipStream, decompressedBuffer);
Console.WriteLine("Decompressed {0} bytes", totalCount);
if (!GZipTest.CompareData(buffer, buffer.Length, decompressedBuffer, totalCount))
{
Console.WriteLine("Error. The two buffers did not compare.");
}
zipStream.Close();
} // end try
catch (InvalidDataException)
{
Console.WriteLine("Error: The file being read contains invalid data.");
}
catch (FileNotFoundException)
{
Console.WriteLine("Error:The file specified was not found.");
}
catch (ArgumentException)
{
Console.WriteLine("Error: path is a zero-length string, contains only white space, or contains one or more invalid characters");
}
catch (PathTooLongException)
{
Console.WriteLine("Error: The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters.");
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("Error: The specified path is invalid, such as being on an unmapped drive.");
}
catch (IOException)
{
Console.WriteLine("Error: An I/O error occurred while opening the file.");
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("Error: path specified a file that is read-only, the path is a directory, or caller does not have the required permissions.");
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("Error: You must provide parameters for MyGZIP.");
}
}
public static void Main(string[] args)
{
string usageText = "Usage: MYGZIP <inputfilename>";
//If no file name is specified, write usage text.
if (args.Length == 0)
{
Console.WriteLine(usageText);
}
else
{
if (File.Exists(args[0]))
GZipCompressDecompress(args[0]);
}
}
}
--------------------编程问答-------------------- 1,压缩前长度和压缩后长度要分清
2,Write和Read要分清
补充:.NET技术 , C#