I have the following piece of code:
byte[] payloadArray = getPayload();
int size = (HEADER_SIZE+payloadArray.length);
ByteBuffer cmdBuffer = ByteBuffer.allocate(HEADER_SIZE+payloadArray.length);
//create command
ByteBuffer lengthBuf = ByteBuffer.allocate(2);
lengthBuf.order(ByteOrder.BIG_ENDIAN);
lengthBuf.putChar((char)(size-2));
cmdBuffer.put(lengthBuf);
cmdBuffer.put(getFlag());
After the execution of the last command the first two bytes of cmdBuffer should show the value from getFlag() and lengthBuf. Though, this is not visible inside cmdBuffer.
I am not sure what is the issue here. Could someone please help?
I suspect the reason is that there are no remaining bytes in lengthBuf.
From the JavaDoc on putChar(char):
Writes two bytes containing the given char value, in the current byte order, into this buffer at the current position, and then increments the position by two.
From the JavaDoc on put(ByteBuffe):
...
Otherwise, this method copies n = src.remaining() bytes from the given buffer into this buffer, starting at each buffer's current position. The positions of both buffers are then incremented by n.
So the put operation reads from the current position of lengthBuf which is the end and there are no bytes left.
Try lengthBuf.reset() after putChar(...) which should reset the position only. Please note that depending on the buffer implementation reset() might not be supported, but ByteBuffer.allocate() creates a HeapByteBuffer which supports that operation.
Edit:
Oleg Estekhin noted that you'd better use lengthBuf.flip() instead of lengthBuf.reset().
From the JavaDoc:
After a sequence of channel-read or put operations, invoke this method to prepare for a sequence of channel-write or relative get operations.
Related
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) '|');
I am new to Random File Access, and I have encountered one issue - as far as I have understood, RandomAccessFile class provides a Random Access file for reading/writing. I can use seek() method to move to preferable position and start reading or wrting, but does not matter in this case. It is completely the random access? But in FileInputStream I have the same ability
read(bute[] byte, int off, int len)
this method provides me reading from some particular place. So, what is the difference? (I guess, InputStream read all file, but just go through all symbols before off position, but it only my guess).
Looking at the documentation of the read method:
https://docs.oracle.com/javase/7/docs/api/java/io/FileInputStream.html#read(byte[],%20int,%20int)
it states that off is "the start offset in the destination array b". So using this call, you can read the next len bytes from the stream and put them is a certain place in your memory buffer. This does not allow you to skip forward like the seek method of a random access file.
The read method you mention does not let you read from any particular place. It always reads from the "next" position in the stream, where it left off, and it puts the read bytes into the byte array at position off. off is the offset in the output, not the input.
I am trying to encrypt a file(txt, pdf, doc) using Google Tink - streaming AEAD encryption, below is the Java code which I am trying to execute. But all I get is 1 KB output encrypted file and no errors. All Input files whether 2 MB or more than 10 MB, output file will be always of 1 KB. I am unable to figure out what could be going wrong, can someone please help.
TinkConfig.register();
final int chunkSize = 256;
KeysetHandle keysetHandle = KeysetHandle.generateNew(
StreamingAeadKeyTemplates.AES128_CTR_HMAC_SHA256_4KB);
// 2. Get the primitive.
StreamingAead streamingAead = keysetHandle.getPrimitive(StreamingAead.class);
// 3. Use the primitive to encrypt some data and write the ciphertext to a file,
FileChannel ciphertextDestination =
new FileOutputStream("encyptedOutput.txt").getChannel();
String associatedData = "Tinks34";
WritableByteChannel encryptingChannel =
streamingAead.newEncryptingChannel(ciphertextDestination, associatedData.getBytes());
ByteBuffer buffer = ByteBuffer.allocate(chunkSize);
InputStream in = new FileInputStream("FileToEncrypt.txt");
while (in.available() > 0) {
in.read(buffer.array());
System.out.println(in);
encryptingChannel.write(buffer);
}
encryptingChannel.close();
in.close();
System.out.println("completed");
This is all about understanding ByteBuffer and how it operates. Let me explain.
in.read(buffer.array());
This writes data to the underlying array, but since array is decoupled from the state of the original buffer, the position of the buffer is not advanced. This is not good, as the next call:
encryptingChannel.write(buffer);
will now think that the position is 0. The limit hasn't changed either and is therefore still set to the capacity: 256. That means the result of the write operation is to write 256 bytes and set the position to the limit (the position).
Now the read operation still operates on the underlying byte array, and that's still 256 bytes in size. So all next read operations take place perfectly. However, all the write operations will assume that there are no bytes to be written, as the position remains at 256.
To use ByteBuffer you can use FileBuffer.read. Then you need to flip the buffer before writing the read data. Finally, after writing you need to clear the buffer's position (and limit, but that only changes on the last read) to prepare the buffer for the next read operation. So the order is commonly read, flip, write, clear for instances of Buffer.
Don't mix Channels and I/O streams, it will makes your life unnecessarily complicated, and learning how to use ByteBuffer is hard enough all by itself.
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.
I have a ByteBuffer that contains a large file (100 MB):
java.nio.ByteBuffer byteBuffer = ByteBuffer.wrap(multipartFile.getBytes());
writeChannel.write(byteBuffer);
writeChannel.closeFinally();
I can only legally write 1 MB to the writeChannel at a time.
How do I slice up the contents of the ByteBuffer and write only a 1 MB slice at a time into the writeChannel?
You can use ByteBuffer#slice() to get a duplicate view of your base ByteBuffer instance, then bump the position along to expose a sliding window of content. Alternately, you can just do the same to your base buffer if you don't need to expose it to any other consumers.
You can change the starting position of your view of the content via the single-argument Buffer#position(int) method, and change the end position of your view via Buffer#limit(int). So long as you're mindful not to push the view beyond the limit of the underlying buffer, you can do the following:
final ByteBuffer view = base.slice();
for (int start = base.position(), end = base.limit(), stride = 1000000;
start != end;
start = view.limit())
consume(view.position(start)
.limit(start + Math.min(end - start, stride)));
I didn't test it, but it looks correct. It's possible to rewrite to avoid the initial setting of the position, which isn't strictly necessary here, but it incurs either some repetition or more awkward special case treatment of the first time through.
I left it this way to preserve the basic for loop structure.
As far as I know, write() on the writeChannel (which for the name I supposed is of type SocketChannel) will "attempt to write up to r bytes to the channel, where r is the number of bytes remaining in the buffer, that is, dst.remaining(), at the moment this method is invoked". (according to this)
The description of ByteBuffer.remaining() says that this method will "Return the number of elements between the current position and the limit."
So my guessing is not that you can't write the entire ByteBuffer, but that your code should call flip() on the ByteBuffer object so it become:
java.nio.ByteBuffer byteBuffer = ByteBuffer.wrap(multipartFile.getBytes());
byteBuffer.flip();
writeChannel.write(byteBuffer);
writeChannel.closeFinally();
As its said in Buffer.flip(): "After a sequence of channel-read or put operations, invoke this method to prepare for a sequence of channel-write or relative get operations"