I have a serialization code that can serialize an object to a bytebuffer. I want to write the length of the buffer first to the stream followed by the bytebuffer itself. Here is how I am writing to the outputStream:
MyObject = new MyObject();
//fill in MyObject
...
DataOutputStream out = new DataOutputStream(new FileOutputStream("a.txt"));
ByteBuffer buffer = MySerializer.encode(myObject);
int length = buffer.remaining();
out.write(length);
WritableByteChannel channel = Channels.newChannel(out);
channel.write(buffer);
out.close();
I verified this code and it seems to be working fine. But when I try to deserialize, I am not able to do it correctly. Here is the snippet of my deserializer code :
DataInputStream in = new DataInputStream(new FileInputStream("a.txt"));
int objSize = in.readInt();
byte[] byteArray = new byte[objSize];
...
The problem is that the length is not being read properly from stream.
Can anyone help me figure out what am I missing here?
write writes a byte. readInt reads 4 bytes and combines them to make an int.
You probably want to write the length with writeInt (which splits the int into 4 bytes and writes those).
Related
Could I bond readBuf to DataInputStream, I will read some bytes to readBuf, and I will read int and other data from DataInputStream which bond to readBuf. Can I do below code?
byte[] readBuf = new byte[MAX_BYTE_SIZE ];
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(readBuf));
writeBytes( UartCmd[1] );
i_ReadLength = readBytes(readBuf);
uc_Index = dis.readInt();
writeBytes( i_WritedLength );
i_ReadLength = readBytes(readBuf);
uc_Index = dis.readInt();
thinks all your help.
I suggest java.nio.ByteBuffer
...
uc_Index = ByteBuffer.wrap(readBuf).getInt();
writeBytes( i_WritedLength );
i_ReadLength = readBytes(readBuf);
uc_Index = ByteBuffer.wrap(readBuf).getInt();
You already have "bonded" a byte[] buffer to an input stream with this line:
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(readBuf));
That should work with dis.readInt(); just fine. Loop over it for as many int's as you expect to be in the buffer.
I can't tell you what's going to happen with readBytes() and writeBytes() since you haven't defined them. The name i_ReadLength seems to mean something completely different than what I'd expect a method named readBytes() to return. Your compiler won't care but us humans do.
If you're hoping to be able to look inside readBuf and tell how many int's have been added to it you're likely going to be disappointed. A byte array of int's is not going to be null terminated like a string would be. You MUST keep track of how much of the readBuf has been initialized with integers somewhere or you will end up reading garbage (data that was never written and could have any value).
What you could do is make the first int in the byte array the count of all the other int's in the array. Once you read that you know how many times to loop. Make sure to set it to the correct value when you write it. Also don't write in to many int's and overflow the byte array. Remember byte's and int's are different sizes.
If that's what you've done don't reinvent the wheel. Do it like this:
byte[] readBuf = getSizePrefixedByteArrayOfInts();
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(readBuf));
//writeBytes( UartCmd[1] ); //Seriously, I've no idea what this does
int i_ReadLength = dis.readInt();
int[] readInts = new int[i_ReadLength];
for(int i = 0; i < i_ReadLength; i++) {
readInts[i] = dis.readInt();
}
Critical to understand here is that this code expects the length counter itself to NOT be counted. If the counter is the only int initialized in the buffer then it's value should be zero. So here's test some code that does that:
private byte[] getSizePrefixedByteArrayOfInts() {
ByteArrayOutputStream baos = null;
DataOutputStream dos = null;
int[] buf = {65, 66, 67, 68, 69, 70, 71};
try{
// create byte array output stream
baos = new ByteArrayOutputStream();
// create data output stream
dos = new DataOutputStream(baos);
// write number of other ints in array
dos.write(buf.length);
// write to the stream from integer array
for(int i: buf)
{
dos.write(i);
}
// flushes bytes to underlying output stream
dos.flush();
return baos.toByteArray();
}catch(Exception e){
// if any error occurs
e.printStackTrace();
}finally{
// releases all system resources from the streams
if(baos!=null)
baos.close();
if(dos!=null)
dos.close();
}
}
My thanks to tutorialspoint for the bulk of getSizePrefixedByteArrayOfInts() code.
How to read first 2 bytes from input stream and convert 2 bytes data into actual int length value, then read and copy the rest of message into byte array.
The rest of data array should be defined after reading first 2 bytes from the stream, does anyone know efficient logic?
Use a DataInputStream. Use the readUnsignedShort() method to return the length word, then the readFully() method to read the following data.
This creates a string from a byte array. Adapt as needed.
InputStream in;
try {
in = socket.getInputStream();
DataInputStream dis = new DataInputStream(in);
int len = dis.readInt();
byte[] data = new byte[len];
if (len > 0) {
dis.readFully(data);
}
String sReturn = new String(data);
}
Given the following pseudo code. how would I do read in the given data
Use DataInputStream to make your life easy.
DataInputStream in = new DataInputStream(socket.getInputStream());
short myShortStreamSize = in.readShort();
byte[] payload = new byte[myShortStreamSize];
in.readFully(payload);
Socket has a getInputStream() method. You would use the returned InputStream and read myShortStreamSize of bytes from it into a byte[], convert that into a int/long representing your payload size and then read into another, larger, new byte[payloadSize], the payload itself.
You can try JBBP
#Bin class Struct { byte [] payload; }
#Bin class ParsedStream { Struct [] structs; }
ParsedStream parsed = JBBPParser.prepare("structs[_] { ushort size; byte [size] payload; }").parse(theInStream).mapTo(ParsedStream.class);
I am trying to first read 4 bytes(int) specifying the size of the message and then read the remaining bytes based on the byte count. I am using the following code to accomplish this:
DataInputStream dis = new DataInputStream(
mClientSocket.getInputStream());
// read the message length
int len = dis.readInt();
Log.i(TAG, "Reading bytes of length:" + len);
// read the message data
byte[] data = new byte[len];
if (len > 0) {
dis.readFully(data);
} else {
return "";
}
return new String(data);
Is there a better/efficient way of doing this?
From JavaDocs of readUTF:
First, two bytes are read and used to construct an unsigned 16-bit
*integer* in exactly the manner of the readUnsignedShort method . This
integer value is called the UTF length and specifies the number of
additional bytes to be read. These bytes are then converted to
characters by considering them in groups. The length of each group is
computed from the value of the first byte of the group. The byte
following a group, if any, is the first byte of the next group.
The only problem with this is that your protocol seems to only send 4 bytes for the payload length. Perhaps you can do a similar method but increase the size of length sentinel read to 4 bytes/32-bits.
Also, I see that you are just doing new String(bytes) which works fine as long as the encoding of the data is the same as "the platform's default charset." See javadoc So it would be much safer to just ensure that you are encoding it correctly(e.g. if you know that the sender sends it as UTF-8 then do new String(bytes,"UTF-8") instead).
How about
DataInputStream dis = new DataInputStream(new BufferedInputStream(
mClientSocket.getInputStream()));
return dis.readUTF();
You can use read(byte[] b, int off, int len) like this
byte[] data = new byte[len];
dis.read(data,0,len);
How can I convert DataInput to DataInputStream in java?
I need to know the size of the DataInput.
Since a stream, by definition, really has no begining or end and thus no fool proof way of knowing how much is available, you just have to read from the stream in fixed sized chunks. It almost sounds like you'd be better off with plain old .read() rather than readFully():
DataInputStream dis = new DataInputStream(...);
byte[] buf = new byte[1024];
int lastRead = 0;
do {
lastRead = dis.read(buf);
//do something with 'buf' here
} while (lastRead > 0);
You'll encounter difficulty when you want know how many bytes to be read. Simplest solution is to cast it to a ByteArrayInputStream and use it's available() method to get to know how many bytes are available for reading.
Following example worked for me
DataInput in = (...);
ByteArrayInputStream bis = (ByteArrayInputStream) in;
byte[] buffer = new byte[bis.available()];
in.readFully(buffer);
//use buffer as your wish