我有下面的C代码,它应该将任意对象序列化为字符串,然后当然反序列化它。
public static string Pack(Message _message)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream original = new MemoryStream();
MemoryStream outputStream = new MemoryStream();
formatter.Serialize(original, _message);
original.Seek(0, SeekOrigin.Begin);
DeflateStream deflateStream = new DeflateStream(outputStream, CompressionMode.Compress);
original.CopyTo(deflateStream);
byte[] bytearray = outputStream.ToArray();
UTF8Encoding encoder = new UTF8Encoding();
string packed = encoder.GetString(bytearray);
return packed;
}
public static Message Unpack(string _packed_message)
{
UTF8Encoding encoder = new UTF8Encoding();
byte[] bytearray = encoder.GetBytes(_packed_message);
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream input = new MemoryStream(bytearray);
MemoryStream decompressed = new MemoryStream();
DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress);
deflateStream.CopyTo(decompressed); // EXCEPTION
decompressed.Seek(0, SeekOrigin.Begin);
var message = (Message)formatter.Deserialize(decompressed); // EXCEPTION 2
return message;
}
但问题是,无论何时运行代码,我都会遇到异常。使用上面的代码并调用它,如下所示,我接收到invaliddataexception:unknown块类型。流可能已损坏。在标记的
// EXCEPTION
行。在寻找这个问题之后,我试图摆脱通货紧缩。这只是一个很小的变化:在
Pack
中,bytearray
是从original.ToArray()
创建的,在Unpack
中,我Seek()
input
而不是decompressed
并使用Deserialize(input)
而不是decompressed
。唯一改变的结果是:异常位置和主体不同,但它仍然发生。我收到序列化异常:对象“201326592”没有映射。在// EXCEPTION 2
处。我好像看不出有什么问题。也许这是整个系列化的想法…问题在于,以某种方式打包
Message
实例是必要的,因为这些对象保存在服务器和客户机应用程序之间传递的信息。(序列化逻辑位于两端都引用的.shared dll项目中,但是,现在,我只是先开发服务器端。)还必须告诉您,我只使用string
输出,因为现在服务器和客户端之间的TCP连接是基于两端的字符串读写。所以无论如何,它必须降到弦的水平。消息对象的外观如下:
[Serializable]
public class Message
{
public MessageType type;
public Client from;
public Client to;
public string content;
}
(
Client
现在是一个空类,只有Serializable
属性,没有属性或方法。)这就是调用pack unpack的方式(从
Main()
..): Shared.Message msg = Shared.MessageFactory.Build(Shared.MessageType.DEFAULT, new Shared.Client(), new Shared.Client(), "foobar");
string message1 = Shared.MessageFactory.Pack(msg);
Console.WriteLine(message1);
Shared.Message mess2 = Shared.MessageFactory.Unpack(message1); // Step into... here be exceptions
Console.Write(mess2.content);
这是一张显示ide中发生的事情的图片。控制台窗口中的输出是
message1
的值。不幸的是,一些调查还显示问题可能存在于
bytearray
变量周围。当运行Pack()
时,在编码器创建字符串后,数组包含152个值,但是在Unpack()
中解码后,数组有160个值。我很感激你的帮助,因为我真的没有主意了,有了这个问题,进步就成了障碍。谢谢您。
(更新)最终解决方案:
我要感谢大家的回答和评论,因为我已经达成了解决方案。谢谢您。
Marc Gravell是对的,我错过了
deflateStream
的关闭,因此,结果要么是空的,要么是损坏的。我花了我的时间,重新思考和重写了方法,现在它工作得完美无瑕。甚至通过网络流发送这些字节的目的也在起作用。此外,正如Eric J.所建议的,当数据在
ASCIIEnconding
中流动时,我已经切换到使用string
来进行byte[]
和Stream
之间的更改。固定代码如下:
public static string Pack(Message _message)
{
using (MemoryStream input = new MemoryStream())
{
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(input, _message);
input.Seek(0, SeekOrigin.Begin);
using (MemoryStream output = new MemoryStream())
using (DeflateStream deflateStream = new DeflateStream(output, CompressionMode.Compress))
{
input.CopyTo(deflateStream);
deflateStream.Close();
return Convert.ToBase64String(output.ToArray());
}
}
}
public static Message Unpack(string _packed)
{
using (MemoryStream input = new MemoryStream(Convert.FromBase64String(_packed)))
using (DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress))
using (MemoryStream output = new MemoryStream())
{
deflateStream.CopyTo(output);
deflateStream.Close();
output.Seek(0, SeekOrigin.Begin);
BinaryFormatter bformatter = new BinaryFormatter();
Message message = (Message)bformatter.Deserialize(output);
return message;
}
}
现在一切都发生得很好,如下面的截图所示。这是最初的预期产出。服务器和客户端可执行文件相互通信,消息传播…它被正确地序列化和非序列化。
最佳答案
除了现有的关于编码与BASE-64的观察,请注意,你还没有关闭通缩流。这很重要,因为压缩流缓冲区:如果不关闭,它可能不会写入结束。对于一个短流,这可能意味着它什么都不写。
using(DeflateStream deflateStream = new DeflateStream(
outputStream, CompressionMode.Compress))
{
original.CopyTo(deflateStream);
}
return Convert.ToBase64String(outputStream.GetBuffer(), 0,
(int)outputStream.Length);