当前位置:编程学习 > C#/ASP.NET >>

向高手请教解压缩反序列化的问题

下面的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]; 解压后的大小不是这个

你返回了一个空~~然后去反序列化空~~ --------------------编程问答--------------------

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();  
  } 

--------------------编程问答-------------------- 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();  } 
--------------------编程问答-------------------- 不要意思 
把函数myDecompress2(byte[] data)里第一句更正如下:
MemoryStream ms = new MemoryStream(data);   --------------------编程问答-------------------- 回3楼
没有buffer.ToArray()这个方法 --------------------编程问答--------------------
引用 5 楼 yangxinglouis 的回复:
回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#
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,