【问题标题】:Read or convert to Int32 from TWO byte arrays从两个字节数组中读取或转换为 Int32
【发布时间】:2010-09-06 22:38:30
【问题描述】:

我有 4 个字节,代表一个存储在 2 个单独的字节数组中的整数。我想将这些转换为 Int32 而不复制到第三个字节数组并使用 memorystream 读取它。

数据被分成两个字节数组的原因是因为这是我的问题的一个简化示例,它涉及到无法放入单个字节数组的大量数据。

有什么方法可以实现吗?我不希望将两个字节数组连接成一个 thrid,因为这对我来说至关重要的性能影响。

月亮

【问题讨论】:

  • 您使用什么语言?什么平台?
  • 请在以后的问题中添加尽可能多的相关信息。每个问题最多可以使用 5 个标签。
  • 数据存储在一个字节[Max Int Size][]
  • 我建议您进行一些认真的性能测量。对此的通用解决方案相当复杂,而复制到数组的标准做法可能会快很多。

标签: c# bytearray


【解决方案1】:

你可以使用这样的结构布局

[StructLayout(LayoutKind.Explicit, Size=4)]
struct UnionInt32Value
{
[FieldOffset(0)] public byte byte1;
[FieldOffset(1)] public byte byte2;
[FieldOffset(2)] public byte byte3;
[FieldOffset(3)] public byte byte4;
[FieldOffset(0)] public Int32 iVal;
}

以正确的顺序分配您的字节,然后从 iVal 读取您的 Int32;

编辑:示例代码

using System;
using System.Runtime.InteropServices;
namespace Test
{
 class Program
 {
  [StructLayout(LayoutKind.Explicit, Size=4)]
  struct UnionInt32Value
  {
   [FieldOffset(0)] public byte byte1;
   [FieldOffset(1)] public byte byte2;
   [FieldOffset(2)] public byte byte3;
   [FieldOffset(3)] public byte byte4;
   [FieldOffset(0)] public Int32 iVal;
  }
  public static void Main(string[] args)
  {
   UnionInt32Value v = new UnionInt32Value();
   v.byte1=1;
   v.byte2=0;
   v.byte3=0;
   v.byte4=0;
   Console.WriteLine("this is one " + v.iVal);

   v.byte1=0xff;
   v.byte2=0xff;
   v.byte3=0xff;
   v.byte4=0xff;
   Console.WriteLine("this is minus one " + v.iVal);

   Console.Write("Press any key to continue . . . ");
   Console.ReadKey(true);
  }
 }
}

【讨论】:

  • 这看起来很有趣,但我以前没有使用过这种方法。你介意给我一个非常简单的例子,说明它如何与两个字节数组一起使用,第一个数组中的 1 个字节和第二个中的 3 个字节。我将不胜感激。
  • 我一直在阅读 structs 和 fieldoffset。要使用它,我仍然需要将现有数组中的字节复制到结构中,对吗?所以这可能会很慢?或者“struct”可以只指向我数组中的偏移量吗?
  • 如果没有某种形式的复制,就无法做你需要做的事情。这可能与 C# 中的效率一样高。您只使用一个结构作为临时缓冲区。无论如何,当问题出现之前,我会担心性能。
  • @ManInMoon:您需要以某种方式“复制”字节,否则您无法获得 int。像这样复制字节可能是最有效的方法..
  • 感谢您提供的示例 - 这真的很有帮助。目前我用 MemoryStream.readInt32 读取了我的字节数组。我相信这不会复制。由于我的数据大小为 10G,因此性能已经出现问题。如果不是将单字节放入结构中,而是放入字节数组-这仍然有效吗?是否会通过 ref 进行“传递”,以免复制?
【解决方案2】:

这样的?

int x = (array1[index] << 16) + array2[index];

当然,您没有指定语言,但这就是它的要点。

【讨论】:

  • 此解决方案是否假定每个数组中有 2 个字节?我想做的是跨数组边界“读取”。所以我可能在第一个数组的末尾有 1 个字节,在第二个数组的开头有 3 个字节。 OR 3 在第一个数组的末尾和 1 在第二个数组的开头。有没有办法让你的解决方案更通用?顺便说一句,它是 c#。
  • 这是 C,因此显然与您的问题无关。
  • 耻辱 - 没有 c# 版本吗?
  • @ManInMoon 我会说我在 C# 中的答案与 tyrlel 相同。您只需要在 C# 中进行一些转换和 BitConverter,这样您就可以避免符号扩展。
  • 你能给我一个如何使用它的简单例子吗?
【解决方案3】:

BitConverter 类用于此目的:

byte[] parts = { byte1, byte2, byte3, byte4 };
int value = BitConverter.ToInt32(parts, 0);

【讨论】:

    【解决方案4】:

    你可以使用BitConverter两次,比如:

    byte[] bytes0 = new byte[] { 255, 255 };
    byte[] bytes1 = new byte[] { 0, 0 };
    
    int res = BitConverter.ToInt16(bytes0, 0) << 16;
    res |= BitConverter.ToUInt16(bytes1, 0);
    

    产生-65536 (0b11111111 11111111 00000000 00000000)

    如果您的整数部分不在数组中的位置 0,您只需替换 ToUint16 中的 0 即可更改位置。

    小扩展方法:

    public static class BitConverterExt
    {
        public static int ToInt32(byte[] arr0, int index0, byte[] arr1, int index1)
        {
            int partRes = BitConverter.ToInt16(arr1, index1) << 16;
            return partRes | BitConverter.ToUInt16(arr0, index0);
        }
    }
    

    用法:

    byte[] bytes0 = new byte[] { 0x0, 0xA };
    byte[] bytes1 = new byte[] { 0x64, 0xFF };
    
    int res = BitConverterExt.ToInt32(bytes0, 0, bytes1, 0);
    
    //Res -10221056 (0xFF640A00)
    

    【讨论】:

    • 您认为这与将数据复制到新的联合字节数组并直接转换相比在速度方面如何?
    • @ManInMoon 我会说这是你能做到的最快速度。如果您希望它更快,您应该在 C# 中使用指针(BitConverter 在内部执行此操作 - 但它会进行一些可能是多余的检查),但除非它非常重要,否则您不应该这样做。检查各种方法中发生的情况的一个好工具是使用 Reflector。
    • (我刚刚将res += ... 更改为res |= ...,这应该会更快并给出相同的结果)
    【解决方案5】:

    如果我理解正确,您在读取两个数组的边界时会遇到问题。如果是这样,该例程将读取两个数组中任意位置的整数,即使它跨越两个数组。

        int ReadInteger(byte[] array1, byte[] array2, int offset)
        {
            if (offset < 0 || (offset + 4) > (array1.Length + array2.Length))
                throw new ArgumentOutOfRangeException();
    
            if (offset <= (array1.Length - 4))
                return BitConverter.ToInt32(array1, offset);
            else if (offset >= array1.Length)
                return BitConverter.ToInt32(array2, offset - array1.Length);
            else
            {
                var buffer = new byte[4];
                var numFirst = array1.Length - offset;
    
                Array.Copy(array1, offset, buffer, 0,        numFirst);
                Array.Copy(array2, 0,      buffer, numFirst, 4 - numFirst);
    
                return BitConverter.ToInt32(buffer, 0);
            }
        }
    

    注意:根据整数的存储方式,您可能需要更改字节的复制顺序。

    【讨论】:

    • 嗨 Mohammad,是的 - 这可以完成这项工作。但是我很想避免使用 Array.Copy 部分!这将大大增加我的处理时间。数据已经在内存中_我只想在没有副本的情况下从两个地方读取。我想做类似的事情:
    • return BitConverter.ToInt32(MyJoin(bufferA[2,3],bufferB[7,1]), 0);
    • @ManInMoon 是的,看我的回答,这相当于 tylerl 的回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 2015-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多