ushort数组到字节数组

时间:2011-01-15 13:58:47

标签: c# arrays

我有一组ushorts,每个ushort代表一个12位字。这需要紧密压缩到一个字节数组中。它最终应该是这样的:

|  word1    |  word2    |  word3    |  word4   |
| byte1 | byte2 | byte3 | byte4 | byte5 | byte6|

由于每个字只使用12位,因此2个字将打包成3个字节。

有人可以帮忙吗?我在C#中有点担心如何做到这一点。

5 个答案:

答案 0 :(得分:2)

你可能不得不蛮力。

我不是C#家伙,但是你正在寻找(C语言)中的某些内容:

unsigned incursor, outcursor;
unsigned inlen = length(inputarray);  // not literally
for(incursor=0,outcursor=0;incursor < inlen; incursor+=2,outcursor+=3{
   outputarray[outcursor+0] = ((inputarray[incursor+0]) >> 4) & 0xFF;
   outputarray[outcursor+1] = ((inputarray[incursor+0] & 0x0F)<<4 | ((inputarray[incursor+1]>>8) & 0x0F);
   outputarray[outcursor+2] = inputarray[incursor+1] & 0xFF;
}

答案 1 :(得分:2)

如果你想在内存中将数组用作UInt16的数组,然后将其转换为打包的字节数组进行存储,那么你需要一个函数来进行一次性转换。两种数组类型。

public byte[] PackUInt12(ushort[] input)
{
    byte[] result = new byte[(input.Length * 3 + 1) / 2]; // the +1 leaves space if we have an odd number of UInt12s. It's the unused half byte at the end of the array.
    for(int i = 0; i < input.Length / 2; i++)
    {
        result[i * 3 + 0] = (byte)input[i * 2 + 0];
        result[i * 3 + 1] = (byte)(input[i * 2 + 0] >> 8 | input[i * 2 + 1] << 4);
        result[i * 3 + 2] = (byte)(input[i * 2 + 1] >> 4);
    }
    if(input.Length % 2 == 1)
    {
        result[i * 3 + 0] = (byte)input[i * 2 + 0];
        result[i * 3 + 1] = (byte)(input[i * 2 + 0] >> 8);
    }
    return result;
}

public ushort[] UnpackUInt12(byte[] input)
{
    ushort[] result = new ushort[input.Length * 2 / 3];
    for(int i = 0; i < input.Length / 3; i++)
    {
        result[i * 2 + 0] = (ushort)(((ushort)input[i * 3 + 1]) << 8 & 0x0F00 | input[i * 3 + 0]);
        result[i * 2 + 1] = (ushort)(((ushort)input[i * 3 + 1]) << 4 | input[i * 3 + 1] >> 4;)
    }
    if(result.Length % 2 == 1)
    {
        result[i * 2 + 0] = (ushort)(((ushort)input[i * 3 + 1]) << 8 & 0x0F00 | input[i * 3 + 0]);
    }
    return result;
}

但是,如果您希望在应用程序运行时提高内存使用效率,并将此打包数组作为数组访问,那么您将需要一个返回ushort的类,但是存储他们在byte[]

public class UInt12Array
{
    // TODO: Constructors, etc. 

    private byte[] storage;

    public ushort this[int index] 
    {
        get
        {
            // TODO: throw exceptions if the index is off the array.
            int i = index * 2 / 3;
            if(index % 2 == 0)
                return (ushort)(((ushort)storage[i * 3 + 1]) << 8 & 0x0F00 | storage[i * 3 + 0]);
            else
                return (ushort)(((ushort)storage[i * 3 + 1]) << 4 | storage[i * 3 + 1] >> 4;)
        }
        set
        {
            // TODO: throw exceptions if the index is off the array.
            int i = index * 2 / 3;
            if(index % 2 == 0)
                storage[i * 3 + 0] = (byte)value;
                storage[i * 3 + 1] = (byte)(value >> 8 | storage[i * 3 + 1] & 0xF0);
            else
                storage[i * 3 + 1] = (byte)(storage[i * 3 + 1] & 0x0F | value << 4);
                storage[i * 3 + 2] = (byte)(value >> 4);

        }
    }
}

答案 2 :(得分:1)

为什么不将12位字存储在字节数组中,并提供一个getter和setter方法,用于读取和写入ushort的字节到数组中正确的索引?

答案 3 :(得分:1)

尝试用LINQ解决这个问题很有趣!

警告:仅限娱乐用途 - 请勿在实际代码中使用以下表现异常!

首先尝试 - 组对uints,从每对中创建三个字节,展平列表:

byte[] packedNumbers = (from i in Enumerable.Range(0, unpackedNumbers.Length)
                        group unpackedNumbers[i] by i - (i % 2) into pairs
                        let n1 = pairs.First()
                        let n2 = pairs.Skip(1).First()
                        let b1 = (byte)(n1 >> 4)
                        let b2 = (byte)(((n1 & 0xF) << 4) | (n2 & 0xF00) >> 8)
                        let b3 = (byte)(n2 & 0xFFFF)
                        select new[] { b1, b2, b3 })
                        .SelectMany(b => b).ToArray();

或稍微紧凑,但不太可读:

byte[] packedNumbers = unpackedNumbers
  .Select((Value, Index) => new { Value, Index })
  .GroupBy(number => number.Index - (number.Index % 2))
  .SelectMany(pair => new byte[] {
    (byte)(pair.First().Value >> 4),
    (byte)(((pair.First().Value & 0xF) << 4) | (pair.Skip(1).First().Value & 0xF00) >> 8),
    (byte)(pair.Skip(1).First().Value & 0xFFFF) }).ToArray();

任何人?

char[] hexChars = unpackedNumbers.SelectMany(n => n.ToString("X4").Substring(1, 3)).ToArray();
byte[] packedNumbers = (from i in Enumerable.Range(0, hexChars.Length / 2)
                        select byte.Parse(hexChars[i * 2].ToString() + hexChars[i * 2 + 1], NumberStyles.HexNumber))
                       .ToArray();

答案 4 :(得分:0)

根据给出的评论,我想,目前的答案更可取。

但是关于这一点也应该这样做:

public byte[] ushort2byteArr(ushort[] arr) {
  System.IO.MemoryStream ms = new System.IO.MemoryStream(); 
  System.IO.BinaryWriter bw = new System.IO.BinaryWriter(ms);
  for (int i = 0; i < arr.Length-1;) { // check upper limit! 
      // following is wrong! must extend this to pack 8 12 bit words into 3 uint32! 
      UInt32 tmp = arr[i++] | (arr[i++] << 12) ... ; 
      bw.Write(tmp);
  }
  return ms.ToArray(); 
}

未经测试。把它作为伪代码来获取线索。特别是这个词 - &gt; uint32转换。最后可能需要一些填充?

@edit:为了更好的清理而制作了一个函数