Reputation: 711
I have an application that receives data in binary form through Bluetooth. I read the data using inputstream from a bluetoothsocket to a byte[]. But I must parse all messages, because they must have a given format to be valid. All messages are in binary.
My solution was to convert the byte[] to a string and then split the string and parse all received messages.
An example of the data to parse: 0000000010000001
I should know that the first 8 zeros are the header and 10000001 the real data.
My idea was to create a string (from the byte[]) that represents -> 0000000010000001 using new String(byte[]) and then split the whole string in one byte and check the value, like:
string1 had 00000000 string2 had 10000001
I know that 8 zeros are the header, therefore string2 has the representation of the data.
My question is about the efficiency of this method. Is this the best method to do this in a mobile environment?
Upvotes: 1
Views: 4936
Reputation: 11
It is a very low efficiency way, and is not recommended. To parse binary data, we should have the protocol, and always use bit operation. If you are not fimiliar with that,
FastProto is a better choice, what you need to do is annotating the fileds of the data object, FastProto would help you complete all.
Imagine the binary data has fixed length of 20 bytes:
65 00 7F 69 3D 84 7A 01 00 00 55 00 F1 FF 0D 00 00 00 07 00
The binary data contains 3 different types of signals, the specific protocol is as follows:
Byte Offset | Bit Offset | Data Type(C/C++) | Signal Name | Unit | Formula |
---|---|---|---|---|---|
0 | unsigned char | device id | |||
2-9 | long | time | ms | ||
12-13 | short | temperature | ℃ |
import org.indunet.fastproto.annotation.*;
public class Weather {
@UInt8Type(offset = 0)
int id;
@TimeType(offset = 2)
Timestamp time;
@Int16Type(offset = 12)
int temperature;
}
byte[] bytes= ... // binary need parsing
Weather weather = FastProto.parse(datagram, Weather.class);
Maybe you have noticed that FastProto describes the field information in binary data through annotations, which is very simple and efficient.
Upvotes: 0
Reputation: 873
just FYI, there is free OSS library called Java Binary Block Parser (JBBP), it is compatible with Android (2.1+) and it allows just describe structure of data in text format and automatically parse data stream (or array), if you want to parse whole stream to bits then it can be executed in single string
byte [] parsedBits = JBBPParser.prepare("bit:1 [_];").parse(new byte[]{1,2,3,4,5}).findFieldForType(JBBPFieldArrayBit.class).getArray();
Upvotes: 1
Reputation: 66273
String manipulation for parsing binary data is quite inefficient in terms of speed, memory consumption and also puts quite some burden on the garbage collector - because you always generate new string objects and forget them immediately.
In Java you have several choices to do it better:
DataInputStream
: is a wrapper for an InputStream
where you read bytes, shorts, longs, doubles, etc directly from the stream.ByteBuffers
and "derived" types like ShortBuffer
... these are good for bulkd data transfers and also for binary parsing.As long as your data is byte-aligned, these are easy ways to go. If that's not the case - well, then better learn how to do bit-manipulation using operators like &
, |
, ~
, <<
, >>
.
My suggestion is that you stick to DataInputStream
as long as possible.
Upvotes: 2
Reputation: 20961
Strings are the least efficient way to do this indeed.
If your binary 0000000010000001
is actually byte[] {0, 0, 0, 0, 2, 0, 0, 1}
in decimal, then just check if b[0] == b[1] == b[3] == b[4] == 0
.
Edit: Ignore the "in decimal" part, it's irrelevant as long as you only want to check the if your array begins with 00000000
(i.e. 4 zero bytes)
Upvotes: 0