C#

时间:2016-12-15 23:51:29

标签: c# arrays generics byte endianness

我有以下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字节,我的问题是改变我的初始化函数,使其根据传递的类型大小工作。

我想还应该有 ConvertTo8Bytes ConvertFrom8Bytes 这些我不知道如何制作的功能,因为我设置了 _endianDiff _byteBlock 仅用于4字节。我知道_byteBlock应该有动态大小而不是4,但在这种情况下我不知道如何处理字节序。

在旁注中,我通过将 long 分成2个 int 并将它们存储为两个 int 数组来解决了这个问题但是我这样分配无用的内存只是因为我无法使这个算法起作用。

1 个答案:

答案 0 :(得分:3)

如果您正在尝试获取数字数组的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.");
    }

虽然这个代码有几件事需要考虑......

它确实生成了数组的完整副本,因此如果您正在处理大型数组或性能敏感操作,则可能不是最好的方法。

这适用于任何&#34;原始值类型&#34;数组,应包括所有数字类型,如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)));

它的作用:

  • 验证数组是否只有基本类型。
  • 确定数组中元素的大小 计算要分配的字节数组的长度。
  • 它将数组复制到字节数组。
  • 返回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.");
    }