我有一个结构,可以在整个地方使用,我将其作为byteArray存储在hd上,并发送到其他平台。
我曾经通过获取结构的字符串版本并在序列化期间使用getBytes(utf-8)和getString(utf-8)来完成此操作。有了这个,我想我避免了小和大端的问题?
然而,这是相当多的开销,我现在正在使用它:
public static explicit operator byte[] (Int3 self)
{
byte[] int3ByteArr = new byte[12];//4*3
int x = self.x;
int3ByteArr[0] = (byte)x;
int3ByteArr[1] = (byte)(x >> 8);
int3ByteArr[2] = (byte)(x >> 0x10);
int3ByteArr[3] = (byte)(x >> 0x18);
int y = self.y;
int3ByteArr[4] = (byte)y;
int3ByteArr[5] = (byte)(y >> 8);
int3ByteArr[6] = (byte)(y >> 0x10);
int3ByteArr[7] = (byte)(y >> 0x18);
int z = self.z;
int3ByteArr[8] = (byte)z;
int3ByteArr[9] = (byte)(z >> 8);
int3ByteArr[10] = (byte)(z >> 0x10);
int3ByteArr[11] = (byte)(z >> 0x18);
return int3ByteArr;
}
public static explicit operator Int3(byte[] self)
{
int x = self[0] + (self[1] << 8) + (self[2] << 0x10) + (self[3] << 0x18);
int y = self[4] + (self[5] << 8) + (self[6] << 0x10) + (self[7] << 0x18);
int z = self[8] + (self[9] << 8) + (self[10] << 0x10) + (self[11] << 0x18);
return new Int3(x, y, z);
}
它对我来说效果很好,但我不太确定小/大端是如何工作的。当其他机器接收到我作为bytearray发送的int时,我还需要处理这里的安全事项吗?
答案 0 :(得分:1)
是的,你这样做。通过更改字节序,保留位排序的序列化将遇到麻烦。
取int值385
在bigendian系统中,它将存储为
000000000000000110000001
将它解释为littleendian将其视为 100000011000000000000000 反向转换为8486912
如果您使用BitConverter类,则会有一个书籍属性需要系统的字节序。位转换器也可以为您生成位阵列。
您必须根据序列化或反序列化系统字节顺序决定使用字节序和反转字节数组。
description on MSDN实际上非常详细。为简单起见,他们使用Array.Reverse
。我不确定你为了进行位操作而向/从字节进行转换实际上是最快的转换方式,但这很容易进行基准测试。
答案 1 :(得分:1)
当您的应用程序在使用Big-Endian的系统上运行时,您当前的方法将不起作用。在这种情况下,您根本不需要重新排序。
您不需要自行反转字节数组 并且您不需要通过自己检查系统的结束性
静态方法IPAddress.HostToNetworkOrder
将整数转换为具有big-endian顺序的整数。
静态方法IPAddress.NetworkToHostOrder
会将整数转换为整数,并使用
这些方法将检查系统的Endianness,并且会对整数进行重新排序。
要从整数中获取字节,请使用BitConverter
public struct ThreeIntegers
{
public int One;
public int Two;
public int Three;
}
public static byte[] ToBytes(this ThreeIntegers value )
{
byte[] bytes = new byte[12];
byte[] bytesOne = IntegerToBytes(value.One);
Buffer.BlockCopy(bytesOne, 0, bytes, 0, 4);
byte[] bytesTwo = IntegerToBytes(value.Two);
Buffer.BlockCopy(bytesTwo , 0, bytes, 4, 4);
byte[] bytesThree = IntegerToBytes(value.Three);
Buffer.BlockCopy(bytesThree , 0, bytes, 8, 4);
return bytes;
}
public static byte[] IntegerToBytes(int value)
{
int reordered = IPAddress.HostToNetworkOrder(value);
return BitConverter.GetBytes(reordered);
}
从字节转换为struct
public static ThreeIntegers GetThreeIntegers(byte[] bytes)
{
int rawValueOne = BitConverter.ToInt32(bytes, 0);
int valueOne = IPAddress.NetworkToHostOrder(rawValueOne);
int rawValueTwo = BitConverter.ToInt32(bytes, 4);
int valueTwo = IPAddress.NetworkToHostOrder(rawValueTwo);
int rawValueThree = BitConverter.ToInt32(bytes, 8);
int valueThree = IPAddress.NetworkToHostOrder(rawValueThree);
return new ThreeIntegers(valueOne, valueTwo, valueThree);
}
如果您将BinaryReader
和BinaryWriter
用于保存并发送到其他平台,则可以删除BitConverter和字节数组操作。
// BinaryWriter.Write have overload for Int32
public static void SaveThreeIntegers(ThreeIntegers value)
{
using(var stream = CreateYourStream())
using (var writer = new BinaryWriter(stream))
{
int reordredOne = IPAddress.HostToNetworkOrder(value.One);
writer.Write(reorderedOne);
int reordredTwo = IPAddress.HostToNetworkOrder(value.Two);
writer.Write(reordredTwo);
int reordredThree = IPAddress.HostToNetworkOrder(value.Three);
writer.Write(reordredThree);
}
}
读取值
public static ThreeIntegers LoadThreeIntegers()
{
using(var stream = CreateYourStream())
using (var writer = new BinaryReader(stream))
{
int rawValueOne = reader.ReadInt32();
int valueOne = IPAddress.NetworkToHostOrder(rawValueOne);
int rawValueTwo = reader.ReadInt32();
int valueTwo = IPAddress.NetworkToHostOrder(rawValueTwo);
int rawValueThree = reader.ReadInt32();
int valueThree = IPAddress.NetworkToHostOrder(rawValueThree);
}
}
当然,您可以重构上述方法并获得更清晰的解决方案
或者添加为BinaryWriter
和BinaryReader
的扩展程序。