android 分析二进制数据

svmlkihl  于 2022-11-27  发布在  Android
关注(0)|答案(4)|浏览(204)

我有一个通过蓝牙接收二进制形式数据的应用程序。我使用inputstream从蓝牙套接字读取数据到byte[]。但我必须解析所有消息,因为它们必须具有给定的格式才有效。所有消息都是二进制的。
我的解决方案是将byte[]转换为字符串,然后拆分该字符串并解析所有接收到的消息。
要分析的数据示例:0000000010000001
我应该知道前8个零是头,10000001是真实的数据。
我的想法是使用new String(byte [])创建一个表示-〉0000000010000001的字符串(从byte[]),然后将整个字符串拆分为一个字节并检查值,如下所示:
字符串1具有00000000字符串2具有10000001
我知道8个零是头,因此string 2表示数据。
我的问题是关于这种方法的效率。这是在移动的环境中做到这一点的最佳方法吗?

2ul0zpep

2ul0zpep1#

解析二进制数据的字符串操作在速度、内存消耗方面效率很低,而且还会给垃圾收集器带来相当大的负担--因为您总是生成新的字符串对象,然后立即忘记它们。
在Java中,您有几种选择可以做得更好:

  • DataInputStream:是InputStream的 Package 器,您可以在其中直接从流中读取字节、短整型、长整型、双精度型等。
  • 使用ByteBuffersShortBuffer等“派生”类型的NIO......这些类型适用于批量数据传输和二进制解析。

只要你的数据是字节对齐的,这些方法都很简单。如果不是这样,那么最好学习如何使用&|~<<>>等运算符进行位操作。
我的建议是尽可能长时间地坚持使用DataInputStream

py49o6xq

py49o6xq2#

仅供参考,有free OSS library called Java Binary Block Parser (JBBP),它与Android(2.1+)兼容,允许以文本格式描述数据结构并自动解析数据流(或数组),如果您想将整个流解析为位,则可以在单个字符串中执行

byte [] parsedBits = JBBPParser.prepare("bit:1 [_];").parse(new byte[]{1,2,3,4,5}).findFieldForType(JBBPFieldArrayBit.class).getArray();
tp5buhyn

tp5buhyn3#

字符串确实是最低效的方法。
如果你的二进制0000000010000001实际上是十进制的byte[] {0, 0, 0, 0, 2, 0, 0, 1},那么只要检查一下b[0] == b[1] == b[3] == b[4] == 0
编辑:忽略“十进制”部分,只要您只想检查数组是否以00000000(即4个零字节)开头,这是无关紧要的

yk9xbfzb

yk9xbfzb4#

这是一种效率很低的方法,不推荐。要解析二进制数据,我们应该有协议,并且总是使用位操作。如果你不熟悉,
FastProto(https://github.com/indunet/fastproto)是一个更好的选择,你需要做的是注解数据对象的字段,FastProto会帮助你完成所有。
设想这样一个应用,有一个监控设备实时收集气象数据,并以二进制格式发送到气象站,二进制数据具有20字节的固定长度:
65 00 7F 69 3D 84 7A 01 00 00 55 00 F1 FF 0D 00 00 00 07 00
二进制数据包含8种不同类型的信号,具体协议如下:
| 字节偏移量|位偏移|数据型别(C/C++)|信号名称|单位|公式|
| - -|- -|- -|- -|- -|- -|
| 第0页||无符号字符|装置识别码|||
| 一个|||保留的|||
| 2-9 ||长的|计时器|毫秒||
| 十至十一岁||无符号短整型|湿度|相对湿度%||
| 十二至十三岁||短的|温度,温度|摄氏度||
| 十四至十七岁||无符号整型|压强|帕| p * 0.1|
| 十八|第0页|布尔值|温度有效|||
| 十八|一个|布尔值|有效湿度|||
| 十八|2个|布尔值|有效压力|||
| 十八|第3至7页||保留的|||
| 十九|||保留的|||

import org.indunet.fastproto.annotation.*;

public class Weather {
    @UInt8Type(offset = 0)
    int id;

    @TimeType(offset = 2)
    Timestamp time;

    @UInt16Type(offset = 10)
    int humidity;

    @Int16Type(offset = 12)
    int temperature;

    @UInt32Type(offset = 14)
    long pressure;

    @BoolType(byteOffset = 18, bitOffset = 0)
    boolean temperatureValid;

    @BoolType(byteOffset = 18, bitOffset = 1)
    boolean humidityValid;

    @BoolType(byteOffset = 18, bitOffset = 2)
    boolean pressureValid;
}

调用FastProto::parse()方法将二进制数据反序列化为Java数据对象Weather

// datagram sent by monitoring device.
byte[] datagram = ...   

Weather weather = FastProto.parse(datagram, Weather.class);

如果该项目能解决您的问题,请给予一颗星星,谢谢。

GitHub存储库:https://github.com/indunet/fastproto

相关问题