5

so I am parsing a KNOWN amount of bytes. However, the first two bytes represent some number, then the next one represents a number that's only one byte, but then possibly the next four all represent one number that's large. Is there a better way to parse the data, other than the way I am.

    switch (i) {
            //Status
            case 2:
                temp[3] = bytes[i];
                break;
            case 3:
                temp[2] = bytes[i];
                ret.put("Status", byteArrayToInt(temp).toString());
                break;
            //Voltage
            case 4:
                temp[3] = bytes[i];
                break;
            case 5:
                temp[2] = bytes[i];
                ret.put("Voltage", byteArrayToInt(temp).toString());
                break;
            //Lowest Device Signal
            case 6:
                temp[3] = bytes[i];
                break;
            case 7:
                temp[2] = bytes[i];
                ret.put("Lowest Device Signal", byteArrayToInt(temp).toString());
                clearBytes(temp);
                break;

}

I am looping through the array of bytes and I have a switch that knows which bytes go to which location, for example I know the 2nd and third bytes go to the Status code. So I take them and combine them into an int. the temp byte array is a byte[] temp = new byte[4]. Any better way to do this?

3
  • You can either do it your way, with ad-hoc code, or try to employ some sort of generic parser. If it doesn't get much more complex than the above, and you won't be changing it a lot, then the above ad-hoc approach is probably easier than figuring out a more generic scheme. Commented Aug 1, 2013 at 19:33
  • Are the values of i read from the byte[] itself? Can you provide some additional information for the data structure? Commented Aug 1, 2013 at 19:41
  • Creating the Strings and putting it in a Map is far more expensive than your parsing. Possibly as much as 10x. I would worry about avoiding creating object or setting Map first. Commented Aug 1, 2013 at 19:42

2 Answers 2

11

ByteBuffer can handle this.

byte[] somebytes = { 1, 5, 5, 0, 1, 0, 5 };
ByteBuffer bb = ByteBuffer.wrap(somebytes);
int first = bb.getShort(); //pull off a 16 bit short (1, 5)
int second = bb.get(); //pull off the next byte (5)
int third = bb.getInt(); //pull off the next 32 bit int (0, 1, 0, 5)
System.out.println(first + " " + second + " " + third);

Output
261 5 65541

You can also pull off an arbitrary number of bytes using the get(byte[] dst, int offset, int length) method, and then convert the byte array to whatever data type you need.

Sign up to request clarification or add additional context in comments.

4 Comments

+1 I would keep reading until you have all the bytes you expect to get
I am not getting the right values as I was with my old way... not sure what's happening. parsedData.put("Status", status); parsedData.put("Voltage", String.valueOf(buffer.getShort())); parsedData.put("Lowest Device Signal", String.valueOf(buffer.getShort())); parsedData.put("Lowest Device Signal Address", String.valueOf(buffer.get()));
You also may need to skip the first 2 bytes by calling buffer.getShort() once before getting "status". Recall that your switch cases start at array index 2, not 0.
Smart man, that was the problem, however, I figured that out by my self a while ago. But Nice job picking that up.
5

You can use a DataInputStream to read multiple bytes as ints or shorts. It looks like you only use 2 bytes at a time, so you should be reading shorts instead of ints (which in Java are always 4 bytes).

But in the code example below, I will use your description "However, the first two bytes represent some number, then the next one represents a number that's only one byte, but then possibly the next four all represent one number"

DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes));

//the first two bytes represent some number
ret.put("first", Short.toString(in.readShort()));
//next one represents a number that's only one byte
ret.put("second", Byte.toString(in.readByte()));
//next four all represent one number
ret.put("Lowest Device Signal", Integer.toString(in.readInt()));

5 Comments

I am reading from a BluetoothSocket, and sometimes I read 4 bytes, and sometimes 3 bytes, I only pasted the first 7 cases. (There are 58 cases)
It would still work about the same, just call the appropriate readXXX() method in each of your cases.
@user2635648 extend the DataInputStream and add methods readStatus(), readVoltage() and finally readRecord() or whatever it is the whole block of data you are reading
How does it know to only read the first 2 for in.readShort()?
readShort() means read 2 consecutive bytes as a single value. readInt() means read 4 consecutive bytes as a single value

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.