我有一组对象需要写入二进制文件.
我需要文件中的字节是紧凑的,所以我不能使用BinaryFormatter. BinaryFormatter抛出反序列化需求的各种信息.
如果我试试
byte[] myBytes = (byte[]) myObject
Run Code Online (Sandbox Code Playgroud)
我得到一个运行时异常.
我需要快速,所以我宁愿不复制字节数组.我只是喜欢演员表演byte[] myBytes = (byte[]) myObject!
好的只是为了清楚,我输出文件中没有任何元数据.只是对象字节.打包的对象到对象.根据收到的答案,看起来我将编写低级Buffer.BlockCopy代码.也许使用不安全的代码.
Cry*_*ics 150
将对象转换为字节数组:
// Convert an object to a byte array
public static byte[] ObjectToByteArray(Object obj)
{
BinaryFormatter bf = new BinaryFormatter();
using (var ms = new MemoryStream())
{
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
Run Code Online (Sandbox Code Playgroud)
您只需将此函数复制到您的代码中,然后将需要转换为字节数组的对象发送给它.如果需要再次将字节数组转换为object,可以使用下面的函数:
// Convert a byte array to an Object
public static Object ByteArrayToObject(byte[] arrBytes)
{
using (var memStream = new MemoryStream())
{
var binForm = new BinaryFormatter();
memStream.Write(arrBytes, 0, arrBytes.Length);
memStream.Seek(0, SeekOrigin.Begin);
var obj = binForm.Deserialize(memStream);
return obj;
}
}
Run Code Online (Sandbox Code Playgroud)
您可以将此功能与自定义类一起使用.您只需在类中添加[Serializable]属性即可启用序列化
Guf*_*ffa 38
如果您希望序列化数据非常紧凑,您可以自己编写序列化方法.这样你就可以减少开销.
例:
public class MyClass {
public int Id { get; set; }
public string Name { get; set; }
public byte[] Serialize() {
using (MemoryStream m = new MemoryStream()) {
using (BinaryWriter writer = new BinaryWriter(m)) {
writer.Write(Id);
writer.Write(Name);
}
return m.ToArray();
}
}
public static MyClass Desserialize(byte[] data) {
MyClass result = new MyClass();
using (MemoryStream m = new MemoryStream(data)) {
using (BinaryReader reader = new BinaryReader(m)) {
result.Id = reader.ReadInt32();
result.Name = reader.ReadString();
}
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 31
那么从铸造myObject到byte[]永远不会工作,除非你有一个明确的转换,或者myObject 是一个byte[].你需要的序列化框架的一些实物.那里有很多,包括近乎亲爱的Protocol Buffers.在空间和时间方面,它都非常"精益和平均".
你会发现几乎所有的序列化框架都对你可以序列化的内容有很大的限制,但是 - 由于跨平台,Protocol Buffers比一些更多.
如果你能提出更多要求,我们可以为你提供更多帮助 - 但它永远不会像铸造一样简单......
编辑:只是回应这个:
我需要我的二进制文件来包含对象的字节.只有字节,没有任何元数据.打包的对象到对象.所以我将实现自定义序列化.
请记住,对象中的字节经常是引用...因此您需要弄清楚如何处理它们.
我怀疑你会发现设计和实现自己的自定义序列化框架比你想象的更难.
我个人建议,如果您只需要针对几种特定类型执行此操作,那么您就不必费心试图提出一般的序列化框架.只需在所需的所有类型中实现实例方法和静态方法:
public void WriteTo(Stream stream)
public static WhateverType ReadFrom(Stream stream)
Run Code Online (Sandbox Code Playgroud)
要记住的一件事:如果你有继承,一切都变得更加棘手.没有继承,如果您知道自己的类型,则不需要包含任何类型信息.当然,还有版本控制的问题 - 您是否需要担心不同版本的类型的向后和向前兼容性?
Mar*_*ell 13
你真的在谈论序列化,它可以采取多种形式.由于您需要小型和二进制,协议缓冲区可能是一个可行的选择 - 同时提供版本容错和可移植性.与此不同BinaryFormatter,协议缓冲区有线格式不包括所有类型元数据; 只是非常简洁的标记来识别数据.
在.NET中有一些实现; 特别是
我谦虚地认为protobuf-net(我写的)允许更多的.NET习惯用法与典型的C#类("常规"协议缓冲区倾向于要求代码生成); 例如:
[ProtoContract]
public class Person {
[ProtoMember(1)]
public int Id {get;set;}
[ProtoMember(2)]
public string Name {get;set;}
}
....
Person person = new Person { Id = 123, Name = "abc" };
Serializer.Serialize(destStream, person);
...
Person anotherPerson = Serializer.Deserialize<Person>(sourceStream);
Run Code Online (Sandbox Code Playgroud)
jhi*_*den 13
我接受了Crystalonics的回答并将其转换为扩展方法.我希望其他人会发现它们很有用:
public static byte[] SerializeToByteArray(this object obj)
{
if (obj == null)
{
return null;
}
var bf = new BinaryFormatter();
using (var ms = new MemoryStream())
{
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
public static T Deserialize<T>(this byte[] byteArray) where T : class
{
if (byteArray == null)
{
return null;
}
using (var memStream = new MemoryStream())
{
var binForm = new BinaryFormatter();
memStream.Write(byteArray, 0, byteArray.Length);
memStream.Seek(0, SeekOrigin.Begin);
var obj = (T)binForm.Deserialize(memStream);
return obj;
}
}
Run Code Online (Sandbox Code Playgroud)
这对我有用:
byte[] bfoo = (byte[])foo;
Run Code Online (Sandbox Code Playgroud)
foo 是一个我 100% 确定它是一个字节数组的对象。