在 C# 中将数字数组转换为字节,反之亦然
Generic conversion of number arrays into bytes and vice-versa in C#
我有以下 C# 代码将我的数字数组转换为字节数组,然后将其保存为 base64 字符串,反之亦然,但是它不适用于 long因为 long 是 8 字节的,而我的代码只适用于 4 字节的数字。
private static int _endianDiff1;
private static int _endianDiff2;
private static int _idx;
private static byte[] _byteBlock;
enum ArrayType { Float, Int32, UInt32, Int64, UInt64 }
public static bool SetIntArray(string key, int[] intArray)
{
return SetValue(key, intArray, ArrayType.Int32, 1, ConvertFromInt);
}
public static bool SetLongArray(string key, long[] longArray)
{
return SetValue(key, longArray, ArrayType.Int64, 1, ConvertFromLong);
}
private static bool SetValue<T>(string key, T array, ArrayType arrayType, int vectorNumber, Action<T, byte[], int> convert) where T : IList
{
var bytes = new byte[(4 * array.Count) * vectorNumber + 1];
bytes[0] = Convert.ToByte(arrayType); // Identifier
Initialize();
for (var i = 0; i < array.Count; i++)
{
convert(array, bytes, i);
}
return SaveBytes(key, bytes);
}
private static void ConvertFromInt(int[] array, byte[] bytes, int i)
{
ConvertInt32ToBytes(array[i], bytes);
}
private static void ConvertFromLong(long[] array, byte[] bytes, int i)
{
ConvertInt64ToBytes(array[i], bytes);
}
public static int[] GetIntArray(string key)
{
var intList = new List<int>();
GetValue(key, intList, ArrayType.Int32, 1, ConvertToInt);
return intList.ToArray();
}
public static long[] GetLongArray(string key)
{
var longList = new List<long>();
GetValue(key, longList, ArrayType.Int64, 1, ConvertToLong);
return longList.ToArray();
}
private static void GetValue<T>(string key, T list, ArrayType arrayType, int vectorNumber, Action<T, byte[]> convert) where T : IList
{
if (!PlayerPrefs.HasKey(key))
return;
var bytes = Convert.FromBase64String(PlayerPrefs.GetString(key));
if ((bytes.Length - 1) % (vectorNumber * 4) != 0)
{
Debug.LogError("Corrupt preference file for " + key);
return;
}
if ((ArrayType)bytes[0] != arrayType)
{
Debug.LogError(key + " is not a " + arrayType + " array");
return;
}
Initialize();
var end = (bytes.Length - 1) / (vectorNumber * 4);
for (var i = 0; i < end; i++)
{
convert(list, bytes);
}
}
private static void ConvertToInt(List<int> list, byte[] bytes)
{
list.Add(ConvertBytesToInt32(bytes));
}
private static void ConvertToLong(List<long> list, byte[] bytes)
{
list.Add(ConvertBytesToInt64(bytes));
}
private static void Initialize()
{
if (BitConverter.IsLittleEndian)
{
_endianDiff1 = 0;
_endianDiff2 = 0;
}
else
{
_endianDiff1 = 3;
_endianDiff2 = 1;
}
if (_byteBlock == null)
{
_byteBlock = new byte[4];
}
_idx = 1;
}
private static bool SaveBytes(string key, byte[] bytes)
{
try
{
PlayerPrefs.SetString(key, Convert.ToBase64String(bytes));
}
catch
{
return false;
}
return true;
}
private static void ConvertInt32ToBytes(int i, byte[] bytes)
{
_byteBlock = BitConverter.GetBytes(i);
ConvertTo4Bytes(bytes);
}
private static void ConvertInt64ToBytes(long i, byte[] bytes)
{
_byteBlock = BitConverter.GetBytes(i);
ConvertTo8Bytes(bytes);
}
private static int ConvertBytesToInt32(byte[] bytes)
{
ConvertFrom4Bytes(bytes);
return BitConverter.ToInt32(_byteBlock, 0);
}
private static long ConvertBytesToInt64(byte[] bytes)
{
ConvertFrom8Bytes(bytes);
return BitConverter.ToInt64(_byteBlock, 0);
}
private static void ConvertTo4Bytes(byte[] bytes)
{
bytes[_idx] = _byteBlock[_endianDiff1];
bytes[_idx + 1] = _byteBlock[1 + _endianDiff2];
bytes[_idx + 2] = _byteBlock[2 - _endianDiff2];
bytes[_idx + 3] = _byteBlock[3 - _endianDiff1];
_idx += 4;
}
private static void ConvertFrom4Bytes(byte[] bytes)
{
_byteBlock[_endianDiff1] = bytes[_idx];
_byteBlock[1 + _endianDiff2] = bytes[_idx + 1];
_byteBlock[2 - _endianDiff2] = bytes[_idx + 2];
_byteBlock[3 - _endianDiff1] = bytes[_idx + 3];
_idx += 4;
}
private static void ConvertTo8Bytes(byte[] bytes)
{
}
private static void ConvertFrom8Bytes(byte[] bytes)
{
}
到目前为止,我已经为 int、uint 和 float 工作,因为它们是所有 4 字节,我的问题是更改我的 Initialize 函数,以便它根据传递的类型大小工作。
我想应该还有 ConvertTo8Bytes 和 ConvertFrom8Bytes 函数,我不知道如何制作,因为我设置了 _endianDiff 和 _byteBlock 仅用于 4 字节。我知道 _byteBlock 应该有动态大小而不是 4 但我不知道在这种情况下如何处理字节序。
旁注,我通过将 long 拆分为 2 ints 并将它们存储为两个
解决了这个问题 int 数组,但我正在像这样分配无用的内存只是因为我无法使该算法工作。
如果您所做的只是尝试获取数值数组的 Base64 表示,那么代码似乎很多。我错过了目标吗?
如果您只想从 base64 字符串获取 int 或 long 数组,试试这个:
private static string ConvertArrayToBase64<T>(IList<T> array) where T : struct
{
if (typeof(T).IsPrimitive)
{
int size = System.Runtime.InteropServices.Marshal.SizeOf<T>();
var byteArray = new byte[array.Count * size];
Buffer.BlockCopy(array.ToArray(), 0, byteArray, 0, byteArray.Length);
return Convert.ToBase64String(byteArray);
}
throw new InvalidOperationException("Only primitive types are supported.");
}
private static T[] ConvertBase64ToArray<T>(string base64String) where T : struct
{
if (typeof(T).IsPrimitive)
{
var byteArray = Convert.FromBase64String(base64String);
var array = new T[byteArray.Length / System.Runtime.InteropServices.Marshal.SizeOf<T>()];
Buffer.BlockCopy(byteArray, 0, array, 0, byteArray.Length);
return array;
}
throw new InvalidOperationException("Only primitive types are supported.");
}
虽然这段代码有几件事需要考虑...
它确实制作了数组的完整副本,因此如果您要处理大型数组或对性能敏感的操作,这可能不是最佳方法。
这应该适用于任何 "primitive value type" 数组,它应该包括所有数字类型,如 int、long、uint、float 等。
要演示用法,请参阅此示例:
var longArray = new long[] { 11111, 22222, 33333, 44444 };
var intArray = new int[] { 55555, 66666, 77777, 88888};
string base64longs = ConvertArrayToBase64(longArray);
Console.WriteLine(base64longs);
Console.WriteLine(string.Join(", ", ConvertBase64ToArray<long>(base64longs)));
string base64ints = ConvertArrayToBase64(intArray);
Console.WriteLine(base64ints);
Console.WriteLine(string.Join(", ", ConvertBase64ToArray<int>(base64ints)));
它的作用:
- 验证数组只有原始类型。
- 确定数组中元素的大小
计算要分配的字节数组的长度。
- 它将数组复制到字节数组。
- Returns base64 表示。
互补函数做相反的事情。
更新:这是 .NET 2.0 兼容版本...
private static string ConvertArrayToBase64<T>(IList<T> array) where T : struct
{
if (typeof(T).IsPrimitive)
{
int size = System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));
var byteArray = new byte[array.Count * size];
Buffer.BlockCopy((Array)array, 0, byteArray, 0, byteArray.Length);
return Convert.ToBase64String(byteArray);
}
throw new InvalidOperationException("Only primitive types are supported.");
}
private static T[] ConvertBase64ToArray<T>(string base64String) where T : struct
{
if (typeof(T).IsPrimitive)
{
var byteArray = Convert.FromBase64String(base64String);
var array = new T[byteArray.Length / System.Runtime.InteropServices.Marshal.SizeOf(typeof(T))];
Buffer.BlockCopy(byteArray, 0, array, 0, byteArray.Length);
return array;
}
throw new InvalidOperationException("Only primitive types are supported.");
}
我有以下 C# 代码将我的数字数组转换为字节数组,然后将其保存为 base64 字符串,反之亦然,但是它不适用于 long因为 long 是 8 字节的,而我的代码只适用于 4 字节的数字。
private static int _endianDiff1;
private static int _endianDiff2;
private static int _idx;
private static byte[] _byteBlock;
enum ArrayType { Float, Int32, UInt32, Int64, UInt64 }
public static bool SetIntArray(string key, int[] intArray)
{
return SetValue(key, intArray, ArrayType.Int32, 1, ConvertFromInt);
}
public static bool SetLongArray(string key, long[] longArray)
{
return SetValue(key, longArray, ArrayType.Int64, 1, ConvertFromLong);
}
private static bool SetValue<T>(string key, T array, ArrayType arrayType, int vectorNumber, Action<T, byte[], int> convert) where T : IList
{
var bytes = new byte[(4 * array.Count) * vectorNumber + 1];
bytes[0] = Convert.ToByte(arrayType); // Identifier
Initialize();
for (var i = 0; i < array.Count; i++)
{
convert(array, bytes, i);
}
return SaveBytes(key, bytes);
}
private static void ConvertFromInt(int[] array, byte[] bytes, int i)
{
ConvertInt32ToBytes(array[i], bytes);
}
private static void ConvertFromLong(long[] array, byte[] bytes, int i)
{
ConvertInt64ToBytes(array[i], bytes);
}
public static int[] GetIntArray(string key)
{
var intList = new List<int>();
GetValue(key, intList, ArrayType.Int32, 1, ConvertToInt);
return intList.ToArray();
}
public static long[] GetLongArray(string key)
{
var longList = new List<long>();
GetValue(key, longList, ArrayType.Int64, 1, ConvertToLong);
return longList.ToArray();
}
private static void GetValue<T>(string key, T list, ArrayType arrayType, int vectorNumber, Action<T, byte[]> convert) where T : IList
{
if (!PlayerPrefs.HasKey(key))
return;
var bytes = Convert.FromBase64String(PlayerPrefs.GetString(key));
if ((bytes.Length - 1) % (vectorNumber * 4) != 0)
{
Debug.LogError("Corrupt preference file for " + key);
return;
}
if ((ArrayType)bytes[0] != arrayType)
{
Debug.LogError(key + " is not a " + arrayType + " array");
return;
}
Initialize();
var end = (bytes.Length - 1) / (vectorNumber * 4);
for (var i = 0; i < end; i++)
{
convert(list, bytes);
}
}
private static void ConvertToInt(List<int> list, byte[] bytes)
{
list.Add(ConvertBytesToInt32(bytes));
}
private static void ConvertToLong(List<long> list, byte[] bytes)
{
list.Add(ConvertBytesToInt64(bytes));
}
private static void Initialize()
{
if (BitConverter.IsLittleEndian)
{
_endianDiff1 = 0;
_endianDiff2 = 0;
}
else
{
_endianDiff1 = 3;
_endianDiff2 = 1;
}
if (_byteBlock == null)
{
_byteBlock = new byte[4];
}
_idx = 1;
}
private static bool SaveBytes(string key, byte[] bytes)
{
try
{
PlayerPrefs.SetString(key, Convert.ToBase64String(bytes));
}
catch
{
return false;
}
return true;
}
private static void ConvertInt32ToBytes(int i, byte[] bytes)
{
_byteBlock = BitConverter.GetBytes(i);
ConvertTo4Bytes(bytes);
}
private static void ConvertInt64ToBytes(long i, byte[] bytes)
{
_byteBlock = BitConverter.GetBytes(i);
ConvertTo8Bytes(bytes);
}
private static int ConvertBytesToInt32(byte[] bytes)
{
ConvertFrom4Bytes(bytes);
return BitConverter.ToInt32(_byteBlock, 0);
}
private static long ConvertBytesToInt64(byte[] bytes)
{
ConvertFrom8Bytes(bytes);
return BitConverter.ToInt64(_byteBlock, 0);
}
private static void ConvertTo4Bytes(byte[] bytes)
{
bytes[_idx] = _byteBlock[_endianDiff1];
bytes[_idx + 1] = _byteBlock[1 + _endianDiff2];
bytes[_idx + 2] = _byteBlock[2 - _endianDiff2];
bytes[_idx + 3] = _byteBlock[3 - _endianDiff1];
_idx += 4;
}
private static void ConvertFrom4Bytes(byte[] bytes)
{
_byteBlock[_endianDiff1] = bytes[_idx];
_byteBlock[1 + _endianDiff2] = bytes[_idx + 1];
_byteBlock[2 - _endianDiff2] = bytes[_idx + 2];
_byteBlock[3 - _endianDiff1] = bytes[_idx + 3];
_idx += 4;
}
private static void ConvertTo8Bytes(byte[] bytes)
{
}
private static void ConvertFrom8Bytes(byte[] bytes)
{
}
到目前为止,我已经为 int、uint 和 float 工作,因为它们是所有 4 字节,我的问题是更改我的 Initialize 函数,以便它根据传递的类型大小工作。
我想应该还有 ConvertTo8Bytes 和 ConvertFrom8Bytes 函数,我不知道如何制作,因为我设置了 _endianDiff 和 _byteBlock 仅用于 4 字节。我知道 _byteBlock 应该有动态大小而不是 4 但我不知道在这种情况下如何处理字节序。
旁注,我通过将 long 拆分为 2 ints 并将它们存储为两个
解决了这个问题 int 数组,但我正在像这样分配无用的内存只是因为我无法使该算法工作。
如果您所做的只是尝试获取数值数组的 Base64 表示,那么代码似乎很多。我错过了目标吗?
如果您只想从 base64 字符串获取 int 或 long 数组,试试这个:
private static string ConvertArrayToBase64<T>(IList<T> array) where T : struct
{
if (typeof(T).IsPrimitive)
{
int size = System.Runtime.InteropServices.Marshal.SizeOf<T>();
var byteArray = new byte[array.Count * size];
Buffer.BlockCopy(array.ToArray(), 0, byteArray, 0, byteArray.Length);
return Convert.ToBase64String(byteArray);
}
throw new InvalidOperationException("Only primitive types are supported.");
}
private static T[] ConvertBase64ToArray<T>(string base64String) where T : struct
{
if (typeof(T).IsPrimitive)
{
var byteArray = Convert.FromBase64String(base64String);
var array = new T[byteArray.Length / System.Runtime.InteropServices.Marshal.SizeOf<T>()];
Buffer.BlockCopy(byteArray, 0, array, 0, byteArray.Length);
return array;
}
throw new InvalidOperationException("Only primitive types are supported.");
}
虽然这段代码有几件事需要考虑...
它确实制作了数组的完整副本,因此如果您要处理大型数组或对性能敏感的操作,这可能不是最佳方法。
这应该适用于任何 "primitive value type" 数组,它应该包括所有数字类型,如 int、long、uint、float 等。
要演示用法,请参阅此示例:
var longArray = new long[] { 11111, 22222, 33333, 44444 };
var intArray = new int[] { 55555, 66666, 77777, 88888};
string base64longs = ConvertArrayToBase64(longArray);
Console.WriteLine(base64longs);
Console.WriteLine(string.Join(", ", ConvertBase64ToArray<long>(base64longs)));
string base64ints = ConvertArrayToBase64(intArray);
Console.WriteLine(base64ints);
Console.WriteLine(string.Join(", ", ConvertBase64ToArray<int>(base64ints)));
它的作用:
- 验证数组只有原始类型。
- 确定数组中元素的大小 计算要分配的字节数组的长度。
- 它将数组复制到字节数组。
- Returns base64 表示。
互补函数做相反的事情。
更新:这是 .NET 2.0 兼容版本...
private static string ConvertArrayToBase64<T>(IList<T> array) where T : struct
{
if (typeof(T).IsPrimitive)
{
int size = System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));
var byteArray = new byte[array.Count * size];
Buffer.BlockCopy((Array)array, 0, byteArray, 0, byteArray.Length);
return Convert.ToBase64String(byteArray);
}
throw new InvalidOperationException("Only primitive types are supported.");
}
private static T[] ConvertBase64ToArray<T>(string base64String) where T : struct
{
if (typeof(T).IsPrimitive)
{
var byteArray = Convert.FromBase64String(base64String);
var array = new T[byteArray.Length / System.Runtime.InteropServices.Marshal.SizeOf(typeof(T))];
Buffer.BlockCopy(byteArray, 0, array, 0, byteArray.Length);
return array;
}
throw new InvalidOperationException("Only primitive types are supported.");
}