【问题标题】:Java: Bytes to floats / intsJava:字节到浮点数/整数
【发布时间】:2011-05-29 15:34:08
【问题描述】:

我有一个从 x 平面通过 UDP 发送的字节数组。字节 (4) 都是浮点数或整数… 我试图将它们投射到花车上,但到目前为止没有运气......

示例数组: 字节数据[41] = {-66,30,73,0};

如何将 4 个字节转换为 int 或 float 而不是 float 使用 8 个字节?

【问题讨论】:

  • 数组中的值是代表 1 个 int/float 还是 4 个 int/floats?
  • 嗯...可能是一个 int/float。而float 4字节,而double是8
  • @James 四个字节是一个整数......整个数组(大小 36)包含多个整数和浮点数

标签: java casting floating-point integer bytearray


【解决方案1】:

注意:我推荐@Ophidian's ByteBuffer approach below,它比这更干净。然而,这个答案有助于理解正在进行的位运算。

我不知道您数据的endianness。您基本上需要根据字节的顺序将字节转换为 int 类型,例如:

int asInt = (bytes[0] & 0xFF) 
            | ((bytes[1] & 0xFF) << 8) 
            | ((bytes[2] & 0xFF) << 16) 
            | ((bytes[3] & 0xFF) << 24);

然后您可以使用以下方法转换为浮点数:

float asFloat = Float.intBitsToFloat(asInt);

这基本上是 DataInputStream 在幕后所做的,但它假设您的字节按特定顺序排列。

编辑 - 按位或

OP 要求澄清在这种情况下按位 OR 的作用。虽然这是一个更大的主题,可能会更好地独立研究,但我将简要介绍一下。 Or (|) 是按位运算符,其结果是通过对两个操作数中的每个位进行单独或运算得到的位集合。

例如(二进制)

   10100000
|  10001100
-----------
   10101100

当我建议在上面使用它时,它涉及将每个字节移动到 int 中的唯一位置。所以如果你有字节{0x01, 0x02, 0x03, 0x04},二进制是{00000001, 00000010, 00000011, 00000100},你有这个:

                                  0000 0001   (1)
                        0000 0010             (2 <<  8)
              0000 0011                       (3 << 16)
  | 0000 0100                                 (4 << 24)
  --------------------------------------------------------
    0000 0100 0000 0011 0000 0010 0000 0001   (67 305 985)

当您将两个数字相或并知道两者都没有设置两个对应的位(如这里的情况)时,按位或与加法相同。

另见

【讨论】:

  • 只是一个菜鸟问题:“|”是什么意思做吗?
  • @Jesper 我知道 |例如,在 if 语句中表示 OR,但究竟会发生什么?
  • 感谢您的解释……我想我明白了 :)
  • 这个答案被接受,所以我不想删除它,但 ByteBuffer 是一个更好的解决方案 IMO。另外,我的回答非常草率,实际上是错误的(在将字节转换为整数后我没有&amp; 0xFF,这意味着符号位正在破坏转换)。已修复。
【解决方案2】:

您可能想使用java.nio.ByteBuffer。它有很多方便的方法可以从字节数组中提取不同的类型,并且还应该为您处理大多数字节顺序问题(包括在必要时切换字节顺序)。

byte[] data = new byte[36]; 
//... populate byte array...

ByteBuffer buffer = ByteBuffer.wrap(data);

int first = buffer.getInt();
float second = buffer.getFloat();

如果你知道的话,它还具有将字节数组转换为 int 数组(通过 asIntBuffer() 方法中的 IntBuffer)或浮点数组(通过 asFloatBuffer() 方法中的 FloatBuffer)的奇特功能输入实际上都是一种类型。

【讨论】:

  • 请原谅我的无知,但ByteBuffer 如何为您“处理大多数字节顺序问题”?它怎么可能可能知道您作为开发人员是否期望{00,00,00,01} 代表116,777,216
  • 好吧,当然它不能自动为你检测字节序,但是在你告诉它(使用ByteBuffer::order(ByteOrder))使用哪个字节序(默认情况下它使用ByteOrder::BIG_ENDIAN)之后,一切else 由 ByteBuffer 处理。
  • 注意:即使是其他类型的数据。其他数组助手仍然有效。就像你有一个浮点大小的 int 和一堆浮点数。您可以 putInt(size()) 然后用浮动缓冲区推送浮动。你可以有任何你想要的输入类型,当你有很多相同的类型很长一段时间时,这些助手是最好的。
【解决方案3】:

如下使用DataInputStream

    DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data));
    float f = dis.readFloat();

    //or if it's an int:        
    int i = dis.readInt();

【讨论】:

  • 注意字节顺序不是很重要吗?
  • DataInputStream 使用以下内容(通过 JavaDocs): 数据输入流和数据输出流以稍微修改 UTF-8 的格式表示 Unicode 字符串。 (有关详细信息,请参阅 X/Open Company Ltd.,“文件系统安全 UCS 转换格式 (FSS_UTF)”,X/Open 初步规范,文档编号:P316。此信息也出现在 ISO/IEC 10646,附件 P 中。)请注意,在下表中,最高有效位出现在最左侧的列中。
  • @Berin:DIS 对 UTF-8 的处理与读取浮点数有什么关系?
  • @khachick:仅当两端的字节序不同时。 DataInputStream 采用网络字节顺序。如果数据按照处理字节序的顺序排列。
  • 那段描述了 DataInputStream 的字节顺序。这就是它与这个主题的关系。
【解决方案4】:

您不能只将它们转换为浮点数/整数。您必须将字节转换为 int 或 float。

这是一种简单的方法:

byte [] data = new byte[] {1,2,3,4};
ByteBuffer b = ByteBuffer.wrap(data);
System.out.println(b.getInt());
System.out.println(b.getFloat());

这里有一个合理的讨论:

http://www.velocityreviews.com/forums/t129791-convert-a-byte-array-to-a-float.html

【讨论】:

    【解决方案5】:

    在我看来,ByteBuffer 方法更好,您可以指定数据的包装位置(从哪个字节索引,这里是 0)以及字节序(这里是 BIG_ENDIAN)。

    try {
        float result = ByteBuffer.wrap(data, 0, 4).order(BIG_ENDIAN).getFloat();
    } catch (IndexOutOfBoundsException exception) {
        // TODO: handle exception
    }
    

    类似 getFloat() 的函数存在于 Int、Short、Long...

    【讨论】:

      猜你喜欢
      • 2012-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-08
      • 1970-01-01
      • 2012-12-01
      • 1970-01-01
      相关资源
      最近更新 更多