如何在C#中将对象转换为字节数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1446547/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to convert an object to a byte array in C#
提问by chuckhlogan
I have a collection of objects that I need to write to a binary file.
我有一组需要写入二进制文件的对象。
I need the bytes in the file to be compact, so I can't use BinaryFormatter
. BinaryFormatter
throws in all sorts of info for deserialization needs.
我需要文件中的字节是紧凑的,所以我不能使用BinaryFormatter
. BinaryFormatter
为反序列化需求抛出各种信息。
If I try
如果我尝试
byte[] myBytes = (byte[]) myObject
I get a runtime exception.
我收到运行时异常。
I need this to be fast so I'd rather not be copying arrays of bytes around. I'd just like the cast byte[] myBytes = (byte[]) myObject
to work!
我需要这个速度很快,所以我不想复制字节数组。我只是想让演员byte[] myBytes = (byte[]) myObject
们工作!
OK just to be clear, I cannot have anymetadata in the output file. Just the object bytes. Packed object-to-object. Based on answers received, it looks like I'll be writing low-level Buffer.BlockCopy
code. Perhaps using unsafe code.
好的,要清楚,我在输出文件中不能有任何元数据。只是对象字节。打包的对象到对象。根据收到的答案,看起来我将编写低级Buffer.BlockCopy
代码。也许使用不安全的代码。
回答by Jon Skeet
Well a cast from myObject
to byte[]
is never going to work unless you've got an explicit conversion or if myObject
isa byte[]
. You need a serialization framework of somekind. There are plenty out there, including Protocol Bufferswhich is near and dear to me. It's pretty "lean and mean" in terms of both space and time.
那么从铸造myObject
到byte[]
永远不会工作,除非你有一个明确的转换,或者myObject
是一个byte[]
。你需要的序列化框架的一些实物。那里有很多,包括协议缓冲区,它对我来说是近在咫尺的。就空间和时间而言,它非常“精益求精”。
You'll find that almost all serialization frameworks have significant restrictions on what you can serialize, however - Protocol Buffers more than some, due to being cross-platform.
你会发现几乎所有的序列化框架对你可以序列化的内容都有很大的限制,但是 - 由于是跨平台的,Protocol Buffers 比某些框架更多。
If you can give more requirements, we can help you out more - but it's never going to be as simple as casting...
如果您可以提出更多要求,我们可以为您提供更多帮助 - 但它永远不会像铸造一样简单......
EDIT: Just to respond to this:
编辑:只是为了回应这个:
I need my binary file to contain the object's bytes. Only the bytes, no metadata whatsoever. Packed object-to-object. So I'll be implementing custom serialization.
我需要我的二进制文件来包含对象的字节。只有字节,没有任何元数据。打包的对象到对象。所以我将实现自定义序列化。
Please bear in mind that the bytes in your objects are quite often references... so you'll need to work out what to do with them.
请记住,对象中的字节经常是引用……因此您需要弄清楚如何处理它们。
I suspect you'll find that designing and implementing your own custom serialization framework is harder than you imagine.
我怀疑您会发现设计和实现您自己的自定义序列化框架比您想象的要困难。
I would personally recommend that if you only need to do this for a few specific types, you don't bother trying to come up with a general serialization framework. Just implement an instance method and a static method in all the types you need:
我个人建议,如果您只需要对少数特定类型执行此操作,则不必费心尝试提出通用序列化框架。只需在您需要的所有类型中实现一个实例方法和一个静态方法:
public void WriteTo(Stream stream)
public static WhateverType ReadFrom(Stream stream)
One thing to bear in mind: everything becomes more tricky if you've got inheritance involved. Without inheritance, if you know what type you're starting with, you don't need to include any type information. Of course, there's also the matter of versioning - do you need to worry about backward and forward compatibility with different versions of your types?
要记住的一件事:如果涉及继承,一切都会变得更加棘手。如果没有继承,如果您知道从什么类型开始,就不需要包含任何类型信息。当然,还有版本控制的问题——您是否需要担心与您的类型的不同版本的向后和向前兼容性?
回答by Jason Williams
To access the memory of an object directly (to do a "core dump") you'll need to head into unsafe code.
要直接访问对象的内存(进行“核心转储”),您需要进入不安全的代码。
If you want something more compact than BinaryWriter or a raw memory dump will give you, then you need to write some custom serialisation code that extracts the critical information from the object and packs it in an optimal way.
如果您想要比 BinaryWriter 或原始内存转储更紧凑的东西,那么您需要编写一些自定义序列化代码,从对象中提取关键信息并以最佳方式对其进行打包。
editP.S. It's very easy to wrap the BinaryWriter approach into a DeflateStream to compress the data, which will usually roughly halve the size of the data.
编辑PS 将 BinaryWriter 方法包装到 DeflateStream 中以压缩数据非常容易,这通常会使数据大小大致减半。
回答by Atmocreations
Take a look at Serialization, a technique to "convert" an entire object to a byte stream. You may send it to the network or write it into a file and then restore it back to an object later.
看看Serialization,这是一种将整个对象“转换”为字节流的技术。您可以将其发送到网络或将其写入文件,然后稍后将其恢复回对象。
回答by Marc Gravell
You are really talking about serialization, which can take many forms. Since you want small and binary, protocol buffers may be a viable option - giving version tolerance and portability as well. Unlike BinaryFormatter
, the protocol buffers wire format doesn't include all the type metadata; just very terse markers to identify data.
你真的在谈论序列化,它可以有多种形式。由于您想要小型和二进制,协议缓冲区可能是一个可行的选择 - 提供版本容错性和可移植性。与 不同BinaryFormatter
,protocol buffers 线格式不包括所有类型元数据;只是非常简洁的标记来识别数据。
In .NET there are a few implementations; in particular
在 .NET 中有一些实现;特别是
I'd humbly argue that protobuf-net (which I wrote) allows more .NET-idiomatic usage with typical C# classes ("regular" protocol-buffers tends to demandcode-generation); for example:
我谦虚地认为 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);
回答by Guffa
If you want the serialized data to be really compact, you can write serialization methods yourself. That way you will have a minimum of overhead.
如果希望序列化数据非常紧凑,可以自己编写序列化方法。这样,您将获得最少的开销。
Example:
例子:
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;
}
}
回答by Crystalonics
To convert an object to a byte array:
要将对象转换为字节数组:
// 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();
}
}
You just need copy this function to your code and send to it the object that you need to convert to a byte array. If you need convert the byte array to an object again you can use the function below:
您只需将此函数复制到您的代码中,然后将您需要转换为字节数组的对象发送给它。如果您需要再次将字节数组转换为对象,您可以使用以下函数:
// 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;
}
}
You can use these functions with custom classes. You just need add the [Serializable]
attribute in your class to enable serialization
您可以将这些函数与自定义类一起使用。您只需要[Serializable]
在类中添加属性即可启用序列化
回答by jhilden
I took Crystalonics' answer and turned them into extension methods. I hope someone else will find them useful:
我接受了 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;
}
}
回答by kyy8080
I found another way to convert object in byte[]. Hier is my solution:
我找到了另一种在 byte[] 中转换对象的方法。Hier是我的解决方案:
IEnumerable en = (IEnumerable) myObject;
byte[] myBytes = en.OfType<byte>().ToArray();
Regards
问候
回答by The Berga
This worked for me:
这对我有用:
byte[] bfoo = (byte[])foo;
foo
is an Object that I'm 100% certain that is a byte array.
foo
是一个我 100% 确定它是一个字节数组的对象。
回答by balage
I believe what you're trying to do is impossible.
The junk that BinaryFormatter
creates is necessary to recover the object from the file after your program stopped.
However it is possible to get the object data, you just need to know the exact size of it (more difficult than it sounds) :
我相信你想要做的事情是不可能的。创建
的垃圾BinaryFormatter
是在程序停止后从文件中恢复对象所必需的。
但是,可以获取对象数据,您只需要知道它的确切大小(比听起来更困难):
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;
}
this can be recovered via:
这可以通过以下方式恢复:
public unsafe static dynamic ToObject(byte[] bytes)
{
var rf = __makeref(bytes);
**(int**)(&rf) += 8;
return GCHandle.Alloc(bytes).Target;
}
The reason why the above methods don't work for serialization is that the first four bytes in the returned data correspond to a RuntimeTypeHandle
. The RuntimeTypeHandle
describes the layout/type of the object but the value of it changes every time the program is ran.
EDIT: that is stupid don't do that -->
If you already know the type of the object to be deserialized for certain you can switch those bytes for BitConvertes.GetBytes((int)typeof(yourtype).TypeHandle.Value)
at the time of deserialization.
上述方法对序列化不起作用的原因是返回数据的前四个字节对应一个RuntimeTypeHandle
. 该RuntimeTypeHandle
描述的布局/类型的对象,但它的值改变每次程序是跑时间。
编辑:那很愚蠢,不要这样做-->
如果您已经知道要反序列化的对象的类型,您可以在反序列化时切换这些字节BitConvertes.GetBytes((int)typeof(yourtype).TypeHandle.Value)
。