I currently ran into a actually quite weird problem with the put method of java.nio.bytebuffer and I wondered if you might know the answer to it, so let's get to it.
My goal is it to concatenate some data to a bytebuffer. The problem is after I call the put method it always adds a 0 after the byte array.
Here is the method which has those side effects:
public ByteBuffer toByteBuffer() {
ByteBuffer buffer = ByteBuffer.allocateDirect(1024));
buffer.put(type.name().getBytes()); // 0 added here
data.forEach((key, value) -> {
buffer.putChar('|');
buffer.put(key.getBytes()); // 0 added here
buffer.putChar('=');
buffer.put(value.getBytes()); // 0 added here
});
buffer.flip();
return buffer;
}
Expected Output should look something like this:
ClientData|OAT=14.9926405|FQRIGHT=39.689075|.....
Actual Ouptut where _ represents the 0s:
ClientData_|OAT_=14.9926405_|FQRIGHT_=39.689075_|.....
The documentation doesn't say anything about this side effect.
Also the put method only puts a 0 in between the byte arrays but not at the very end of the buffer.
I assume the method might be wrong or at least not properly documented, but I really have no clue why it would behave that way.
I think you may be slightly misinterpreting what is happening here. I note your comment about "but not at the very end of the buffer".
The \0 is actually coming from the putChar(char) calls, not the put(byte[]) calls. As it says in the docs (emphasis added):
Writes two bytes containing the given char value, in the current byte order
The default byte order is big endian; given that the chars you are writing are in the 7-bit ASCII range, this means "the byte you want" is going to be preceded by 0x00.
If you want to write a byte, use put(byte):
buffer.put((byte) '|');
Related
That is, if I do:
channel.position(0)
channel.read(buffer); // will read in 1st byte of file and so on
vs
channel.position(1)
channel.read(buffer); // will read in 2nd byte of file and so on
Are my assumptions correct? Reading the documentation doesn't really say anything about that so I wanted to make sure
Is FileChannel position(long newPosition) 0-indexed?
Yes.
Reading the documentation doesn't really say anything about that so I wanted to make sure
It is clear to me. The javadoc for position() says:
"Returns: This channel's file position, a non-negative integer counting the number of bytes from the beginning of the file to the current position".
"[A] non-negative integer" means zero or greater. If they had meant one or greater, they would have written "a positive integer" or "a strictly positive integer".
The method is 0-indexed.
Also when you call the read method, then the file position is updated with the number of bytes actually read. The channel’s position() method returns the current position.
The standard idiom when reading from a stream is to check for EOF (-1):
while((bytesRead = inputStream.read(buffer)) != -1)
This seems pretty standard - I checked source for popular libraries like Apache Commons and it seems to be the defacto standard.
Why do we not stop at 0 as well? Wouldn't > -1 be better? Why do whatever work is in the loop when we didn't read anything?
Basically because it would be pointless. Look at the documentation:
If the length of b is zero, then no bytes are read and 0 is returned; otherwise, there is an attempt to read at least one byte. If no byte is available because the stream is at the end of the file, the value -1 is returned; otherwise, at least one byte is read and stored into b.
So unless you're passing in an empty buffer (which is basically a bug in pretty much all cases; I personally wish the method would throw an exception in that case) the return value will never be 0. It will block for at least one byte to be read (in which case the return value will be 1 or more), or for the end of the stream to be reached (in which case the return value will be -1).
I have a ByteBuffer object called msg with the intended message length in the first four bytes, which I read as follows:
int msgLen = msg.getInt();
LOG.debug("Message size: " + msgLen);
If the msgLen is less than some threshold value, I have a partial message and need to cache. In this case, I'd like to put those first four bytes back into the beginning of the message; that is, put the message back together to be identical to pre-reading. For example:
if (msgLen < threshold) {
msg.rewind();
msg.put(msgLen);
Unfortunately, this does not seem to be the correct way to do this. I've tried many combinations of flip, put, and rewind, but must be misunderstanding.
How would I put the bytes back into the write buffer in their original order?
Answer was posted by Andremoniy in comments section. Read operations do not consume bytes in the buffer, so msg.rewind() was adequate. This didn't work in my case because of some other logic in the program, and I incorrectly associated that with a problem at the buffer level.
Suppose each time the buffer of the input-steam read 1000 bytes. There are some start signs and the video name at the beginning of the buffer, before the actual video content, like 100 byte. I don't want to write them into the result buffer. So the first time write 101-999 to the buffer. And the second time I hope to write 1000-1999. Currently, it write 0-999 again, and the result video has an 900 extra bytes before the actually video contents.
Is there anyway to write the buffer skipping the first buffer length? thanks!
I use this code for skipping bytes from a ByteBuffer:
import java.nio.ByteBuffer;
public class Utility {
public static void skip(ByteBuffer bb, int skip) {
bb.position( bb.position() + skip);
}
}
Sophia, you really do need to include example code so people can help, but I see from your tags you are likely asking about NIO's ByteBuffer.
What you want to do is skip the content you don't want by way of the ByteBuffer.position(int) method - there is no magic in the ByteBuffer impl, it is a backing data store (either a byte[] or direct memory reference to OS) and a series of int pointers that refer to conceptual positions in the buffer (start, end, limit, etc.) -- you just want to make sure you "skip" the bytes you don't want, which can be done by moving the position beyond it so the next operation to write out the entire buffer will start from position and go to limit.
What 0 (number of bytes read) returned by InputStream.read(byte[]) and InputStream.read(byte[], int, int) means? How to handle this situation?
To be clear, I mean read(byte[] b) or read(byte[] b, int off, int len) methods which return number of bytes read.
The only situation in which a InputStream may return 0 from a call to read(byte[]) is when the byte[] passed in has a length of 0:
byte[] buf = new byte[0];
int read = in.read(buf); // read will contain 0
As specified by this part of the JavaDoc:
If the length of b is zero, then no bytes are read and 0 is returned
My guess: you used available() to see how big the buffer should be and it returned 0. Note that this is a misuse of available(). The JavaDoc explicitly states that:
It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.
Take a look at the implementation of javax.sound.AudioInputStream#read(byte[] b, int off, int len) ... yuck. They completely violated the standard java.io.InputStream semantics and return a read size of 0 if you request fewer than a whole frame of data.
So unfortunately; the common advice (and api spec) should preclude having to deal with return of zero when len > 0 but even for JDK provided classes you can't universally rely on this to be true for InputStreams of arbitrary types.
Again, yuck.
According to Java API Doc:
http://java.sun.com/j2se/1.4.2/docs/api/java/io/InputStream.html#read(byte[])
It only can happen if the byte[] you passed has zero items (new byte[0]).
In other situations it must return at least one byte. Or -1 if EOF reached. Or an exception.
Of course: it depends of the actual implementation of the InputStream you are using!!! (it could be a wrong one)
I observed the same behavior (reading 0 bytes) when I build a swing console output window and made a reader-thread for stdout and stderr via the following code:
this.pi = new PipedInputStream();
po = new PipedOutputStream((PipedInputStream)pi);
System.setOut(new PrintStream(po, true));
When the 'main' swing application exits, and my console window is still open I read 0 from this.pi.read().
The read data was put on the console window resulting in a race condition some how, just ignoring the result and not updating the console window solved the issue.