2016-12-15 10 views
1

다음과 같은 C# 코드를 사용하여 숫자 배열을 바이트 배열로 변환 한 다음 base64 문자열로 저장하거나 그 반대의 경우도 가능하지만 작동하지 않습니다 이므로 이 8 바이트이고 내 코드가 4 바이트 숫자로만 작동하기 때문입니다.숫자 배열을 바이트로 일반 변환하거나 그 반대로 C#

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) 
{ 

} 

지금까지 나는 그들이 모두 4 바이트이며, 내 문제가 전달 형의 크기에 따라 작동합니다 그래서 내 초기화 기능을 변경하는 것입니다 있기 때문에 UINT플로트, INT을 위해 일하고 있습니다 .

는 또한 ConvertTo8BytesConvertFrom8Bytes 난 단지 4 바이트의 _endianDiff_byteBlock을 설정하기 때문에 내가하는 방법을 모르는 기능이 있어야 같아요. _byteBlock은 4 대신 동적 크기를 가져야한다는 것을 이해합니다. 그러나이 경우 엔디언 니스를 어떻게 처리해야할지 모르겠습니다. 측면 노트에

, 나는 두 INT 배열로 저장 단 2 명 INT들에 을 분할하고이 문제를 해결했다,하지만 난 '해서 다음과 같이 쓸모없는 메모리를 할당하고있어 이 알고리즘을 작동시키지 못했습니다.

+0

[BitConverter 클래스] (https://msdn.microsoft.com/en-us/library/system.bitconverter (v = vs.110) .aspx)를 참고하십시오. – Abion47

+0

'string ConvertToBase64 (IEnumerable list) { var bytes = list.Select (x => BitConverter.GetBytes (x)). SelectMany (x => x) .ToArray(); return Convert.ToBase64String (bytes); }' –

답변

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."); 
    } 

하지만이 코드에 고려해야 할 몇 가지가 ...있다

배열의 완전한 복사본을 만듭니다. 따라서 큰 배열이나 성능에 민감한 작업을 처리하는 경우에는 최선의 방법이 아닐 수도 있습니다.

 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))); 
:

이 등의 사용을 설명하기 위해

INT, 긴, UINT, 플로트, 같은 모든 숫자 유형을 포함해야한다 어떤 "프리미티브 값 유형"어레이와 함께 작동합니다,이 예제를 참조

가 무엇을 :

  • 배열은 기본 유형이 있는지 확인합니다.
  • 배열의 요소 크기를 결정합니다. 할당 할 바이트 배열의 길이를 계산합니다.
  • 배열을 바이트 배열에 복사합니다.
  • 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."); 
    } 
+0

이 코드는 컴파일되지 않습니다. * 일반 인수가 아닌 'Marshal.SizeOf (object)'는 형식 인수와 함께 사용할 수 없습니다. * –

+0

Marshal.SizeOf (object) 또는 Marshal.SizeOf를 사용 중입니다. () ? 코드 예제에서는 후자를 사용하여 컴파일하고 올바르게 실행합니다. 그들은 서로 다른 기능을합니다. 하나는 유형 T를 제네릭 유형으로 전달하고, 다른 하나는 유형을 판별하기 위해 오브젝트를 전달합니다. .NET의 어떤 버전을 사용하고 있습니까? –

+0

예제의 코드를 사용했습니다. Unity를 사용하기 때문에 .NET 2.0에 붙어 있습니다. –