如何将对象转换为C#中的字节数组

我有一个对象的集合,我需要写入二进制文件。

我需要文件中的字节是紧凑的,所以我不能使用BinaryFormatterBinaryFormatter为反序列化需求引发各种信息。

如果我尝试

 byte[] myBytes = (byte[]) myObject 

我得到一个运行时exception。

我需要这是快速的,所以我宁愿不复制字节数组。 我只是喜欢cast byte[] myBytes = (byte[]) myObject工作!

好的只是要清楚,我不能在输出文件中有任何元数据。 只是对象字节。 打包对象到对象。 根据收到的答案,它看起来像我会写低级别的Buffer.BlockCopy代码。 也许使用不安全的代码。

将对象转换为字节数组:

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

你只需要将这个函数复制到你的代码中,并把你需要的对象转换成字节数组。 如果你需要将字节数组转换为对象,你可以使用下面的函数:

 // 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; } } 

你可以使用自定义类的这个function。 您只需在类中添加[Serializable]属性即可启用序列化

如果您希望序列化的数据非常紧凑,您可以自己编写序列化方法。 这样你将有一个最小的开销。

例:

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

那么从myObjectbyte[]是永远不会工作,除非你有一个明确的转换或如果myObject 一个byte[] 。 你需要一个类似的序列化框架。 那里有很多,包括接近和亲爱的Protocol Buffers 。 无论在时间还是空间方面,它都是“精益而又吝啬的”。

你会发现,几乎所有的序列化框架都对你可以序列化的东西有很大的限制,但是由于是跨平台的,协议缓冲区比一些更多。

如果你可以提出更多的要求,我们可以帮助你更多的 – 但它永远不会像铸造一样简单…

编辑:只是回应这个:

我需要我的二进制文件来包含对象的字节。 只有字节,没有任何元数据。 打包对象到对象。 所以我会实现自定义序列化。

请记住,对象中的字节常常是引用,所以你需要弄清楚如何处理它们。

我怀疑你会发现devise和实现你自己的定制序列化框架比你想像的更难。

我个人build议,如果你只需要为几个特定的​​types做这个,你就不用费神去devise一个通用的序列化框架。 只需要在你需要的所有types中实现一个实例方法和一个静态方法:

 public void WriteTo(Stream stream) public static WhateverType ReadFrom(Stream stream) 

有一件事要牢记:如果涉及到inheritance,一切都变得更加棘手。 没有inheritance,如果你知道你开始的是什么types,你不需要包含任何types的信息。 当然,还有版本的问题 – 你需要担心与不同版本的types的向后兼容性?

你真的在谈论序列化,可以采取多种forms。 既然你想要小的和二进制的,协议缓冲区可能是一个可行的select – 给予版本容忍性和可移植性。 与BinaryFormatter不同,协议缓冲区的连线格式不包含所有的types元数据; 只是非常简洁的标记来识别数据。

在.NET中有一些实现; 尤其是

  • protobuf网
  • DOTNET,protobufs

我虚心地说,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); 

我拿了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; } } 

看看序列化 ,一种将整个对象“转换”为字节stream的技术。 您可以将它发送到networking或写入一个文件,然后将其恢复到一个对象。

要直接访问对象的内存(做一个“核心转储”),你需要进入不安全的代码。

如果你想要比BinaryWriter更紧凑的东西,或者原始的内存转储会给你,那么你需要编写一些自定义的序列化代码,从对象中提取关键信息并以最佳方式进行打包。

编辑 PS将BinaryWriter方法包装到DeflateStream中以压缩数据是非常简单的,这通常会使数据大小减半。

我发现另一种方法来转换对象在字节[]。 Hier是我的解决scheme:

 IEnumerable en = (IEnumerable) myObject; byte[] myBytes = en.OfType<byte>().ToArray(); 

问候

这对我工作:

 byte[] bfoo = (byte[])foo; 

foo是一个对象,我100%肯定是一个字节数组。

我相信你想做的事情是不可能的。

BinaryFormatter创build的垃圾在程序停止后需要从文件中恢复对象。
但是可以获取对象数据,只需要知道它的确切大小(比听起来更难):

 public static unsafe byte[] Binarize(object obj, int size) { var r = new byte[size]; var rf = __makeref(obj); var a = **(IntPtr**)(&rf); Marshal.Copy(a, r, 0, size); return res; } 

这可以通过以下方式恢复:

 public unsafe static dynamic ToObject(byte[] bytes) { var rf = __makeref(bytes); **(int**)(&rf) += 8; return GCHandle.Alloc(bytes).Target; } 

上述方法不能用于序列化的原因是返回数据中的前四个字节对应于一个RuntimeTypeHandleRuntimeTypeHandle描述对象的布局/types,但是每次程序运行时,它的值都会改变。

编辑:这是愚蠢的不这样做 – > 如果你已经知道的对象types的反序列化肯定你可以切换这些字节的BitConvertes.GetBytes((int)typeof(yourtype).TypeHandle.Value) at反序列化的时间。

如果你只是有文本或类似的存储,你可以做这样的事情:byte [] byteArray = Encoding.ASCII.GetBytes(myObject.text);

否则,你将不得不以更多的方式进行序列化。

我知道这是一个旧的职位,但它仍然出现在谷歌最高的结果,所以我想补充我怎么做。 我需要传递一个图像(作为一个字节[])在对象的字典。 上述build议不起作用,因为即使我的原始数组将其转换为ObjectToArray方法,转换将输出更改为不同。

最后,这个简单的过程为我工作…

  private object GetByteArray() { byte[] myReturn = new byte[] { 1, 2, 3, 4 }; return Convert.ToBase64String(myReturn); } private byte[] ConvertToByteArray(object myValues) { byte[] myReturn = Convert.FromBase64String(Convert.ToString(myValues)); return myReturn; }