我有以下 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 block type。流可能已损坏。在标记// EXCEPTION
线上。
在搜索了这个问题之后,我试图放弃通货紧缩。这只是一个很小的变化: in Pack
,bytearray
从original.ToArray()
和 in 中创建Unpack
,我Seek()
input
代替decompressed
和使用Deserialize(input)
代替decompressed
太。唯一改变的结果:异常位置和主体不同,但它仍然发生。我收到SerializationException: No map for object '201326592'。在// EXCEPTION 2
.
我似乎没有看到有什么问题。也许这是整个序列化的想法……问题在于以某种方式管理实例是必要的Message
,因为这些对象包含在服务器和客户端应用程序之间传输的信息。(序列化逻辑在两端引用的.Shared DLL 项目中,但是,现在,我只首先开发服务器端。)还必须告诉我,我只使用string
输出,因为现在,服务器和客户端之间的TCP连接是基于字符串读写的。因此,它必须以某种方式降低到字符串的水平。
这是 Message 对象的样子:
[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;
}
}
现在一切都发生得恰到好处,如下图所示。这是最初的预期输出。服务器和客户端可执行文件相互通信并且消息传播......并且它被正确地序列化和反序列化。