3

I have a Java class

public class MsgLayout{
int field1;
String field2;
long field3;
}

I have to write this object as a byte array in a Socket output stream. The three fields (instance variables) have a layout. i.e. field1 must occupy 1 byte, field2 must occupy 4 bytes and field3 must occupy 8 bytes.

ByteBuffer bbf = ByteBuffer.allocate(TOTAL_SIZE);
bbf.put(Integer.toString(this.getField1()).getBytes(), 0, FIELD1_SIZE);
bbf.position(FIELD2_OFFSET);
bbf.put(Long.toString(this.getField2()).getBytes(), 0, FIELD2_SIZE);
bbf.position(FIELD3_OFFSET);
bbf.put(Long.toString(this.getField3()).getBytes(), 0, FIELD3_SIZE);
byte[] msg = bbf.array();

Using the above code, I am trying to fit each field in the byte array according to its desired size. But I am getting IndexOutOfBoundException In short, the problem is about how to fit the fields in the layout-defined size. For Example FIELD1_OFFSET = 0, FIELD1_SIZE=1, FIELD2_OFFSET=1, FIELD2_SIZE=4, FIELD3_OFFSET=5, FIELD3_SIZE=8. Now when I convert field1 into String, it does not fit into 1 byte when converted into byte[]. If I do not convert to String, and use putInt(int) it writes 4 bytes into the resulting byte array.

hoshang.varshney
  • 1,110
  • 3
  • 15
  • 26
  • Unless you can guarantee the range of your fields, you will lose data when attempting to store them into too-small fixed-size slots in the buffer. How do you plan to resolve that? – kdgregory Sep 28 '11 at 14:50
  • What do you mean by range? Can't I fit Integer in one byte? Can't I store a String in 4 bytes? – hoshang.varshney Sep 28 '11 at 19:32
  • @hoshang.varshney, no an int in Java is 4 bytes and a String is variable length. When you say String are you thinking of a char, i.e. a single character? In Java even a single char takes up 2 bytes since it uses unicode. – Mike Deck Sep 28 '11 at 21:34
  • I am referring to String (variable length). I guess I will have to keep field2 max length as 4 so as to fit into the message. – hoshang.varshney Sep 29 '11 at 05:15

2 Answers2

2

What your code is currently doing is encoding your numeric fields as strings and then outputting the bytes of those characters.

I would suggest using the DataOutputStream class to wrap your SocketOutput stream and write your binary data as so:

DataOutput output = new DataOutputStream(socketOutputStream);

int field1 = 1;
String field2 = "Hello";
long field3 = 5000000000L;

output.writeByte(field1);
output.writeBytes(field2.substring(0, 3));
output.writeLong(field3);

There are a couple assumptions in this code. First I'm assuming for field 2 you want 4 characters serialized as a single byte each. If you want to do any multibyte encoding using something like UTF-8, then you need to do something a little differently. Second, I'm assuming that field 2 will always have at least 4 characters.

Mike Deck
  • 18,045
  • 16
  • 68
  • 92
0

field1 may only have one byte of data, but its string representation will be one or more characters (e.g. "0", "63", "127"). Each character in the String is in fact a char (a two byte value). So I would expect one byte of data to inflate to two to six bytes of data when it goes through a byte->String->byte[] conversion.

pamphlet
  • 2,054
  • 1
  • 17
  • 27