如果我尝试使用:
byte[] myBytes = (byte[]) myObject
我遇到了一个运行时异常。
我希望这个过程能够快速进行,所以我不想复制字节数组。我只想让强制转换 byte[] myBytes = (byte[]) myObject
正常工作!
好的,为了明确起见,我不能在输出文件中有 任何 元数据,只能包含对象字节。根据所得到的答案,看起来我需要编写低级别的 Buffer.BlockCopy
代码,可能需要使用不安全代码。
byte[] myBytes = (byte[]) myObject
我遇到了一个运行时异常。
我希望这个过程能够快速进行,所以我不想复制字节数组。我只想让强制转换 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;
}
}
您可以在自定义类中使用这些函数。只需要在您的类中添加[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;
}
}
BinaryWriter
将以BinaryReader
可以读取的格式进行编写,只要你按相同的顺序写入和读取即可。 - GuffaBinaryWriter/Reader
和使用BinaryFormatter
有什么区别? - SmithBinaryWriter/Reader
进行序列化和反序列化,可以自己处理,并且只写入/读取绝对需要的数据,使其尽可能紧凑。 BinaryFormatter
使用反射来查找要写入/读取的数据,并使用适用于所有可能情况的格式。 它还在流中包含有关格式的元信息,因此增加了更多开销。 - Guffaint
(或者如果你已经指定了其他类型作为枚举的存储方式),然后写入。当你读取它时,你可以将其转换为枚举类型。 - Guffa将myObject
转换为byte[]
是永远不可能成功的,除非你有一个明确的转换方法,或者myObject
本身就是一个byte[]
。你需要一种序列化框架来实现这个功能。有很多框架可供选择,包括我比较喜欢的Protocol Buffers。它在空间和时间方面都非常高效。
然而,几乎所有的序列化框架都有严格的限制,特别是跨平台的Protocol Buffers更是如此。
如果您能提供更多的要求,我们可以提供更多的帮助。但是,实现序列化永远不会像强制转换那么简单...
编辑:回应以下内容:
我需要我的二进制文件仅包含对象的字节。仅仅是字节,没有任何元数据。对象之间紧密相连。因此,我将实现自定义序列化。
请记住,对象中的字节经常是引用...所以您需要想好如何处理它们。
我怀疑您会发现设计和实现自己的自定义序列化框架比您想象的要困难得多。
个人建议是,如果您只需要为几种特定类型实现此功能,则不要试图开发通用的序列化框架。只需在所有需要的类型中实现一个实例方法和一个静态方法即可:
public void WriteTo(Stream stream)
public static WhateverType ReadFrom(Stream stream)
需要记住一件事:如果涉及到继承,所有的事情都会变得更加复杂。如果没有继承,如果你知道你所要处理的类型,就不需要包含任何类型信息。当然,还有版本控制的问题 - 你是否需要担心不同版本的类型之间的向前和向后兼容性?
使用二进制格式化程序现在被认为是不安全的。请参见 --> Docs Microsoft
只需使用 System.Text.Json:
将对象序列化为字节:
JsonSerializer.SerializeToUtf8Bytes(obj);
将字节数组反序列化为您的类型:
JsonSerializer.Deserialize(byteArray);
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;
}
}
您正在讨论序列化,它可以采用许多形式。如果您想要小且二进制的数据格式,那么协议缓冲可能是一个可行的选择-同时具有版本容忍性和可移植性。与 BinaryFormatter
不同,协议缓冲线路格式不包括所有类型元数据;只包含非常简洁的标记来识别数据。
.NET中有一些实现;特别是:
我谦虚地认为,protobuf-net(由我编写)允许使用典型的C#类进行更多的 .NET 惯用用法(“常规”协议缓冲 tend to demand 代码生成);例如:
[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);
这对我有用:
byte[] bfoo = (byte[])foo;
foo
是一个对象,我百分之百确定它是一个字节数组。
public TData ByteToObj<TData>(byte[] arr){
return JsonConvert.DeserializeObject<TData>(Encoding.UTF8.GetString(arr));
}
public byte[] ObjToByte<TData>(TData data){
var json = JsonConvert.SerializeObject(data);
return Encoding.UTF8.GetBytes(json);
}
请看序列化,一种将整个对象转换为字节流的技术。您可以将其发送到网络或写入文件,然后稍后将其还原回对象。
BinaryFormatter
。 - Marc Gravell该方法从一个对象返回一个字节数组。
private byte[] ConvertBody(object model)
{
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(model));
}
MemoryStream
的构造函数。这样可以省略使用Write(...)
和Seek(...)
的步骤。 - unknown6656