Junior sister learning java IO: buffer and buff
brief introduction
The younger martial sister goes farther and farther on the road of learning NiO. The only thing that can help her is to give her full support when she needs it. I won't say anything. Today we will introduce the basic buffer of NiO. Old fellow gave me Buff.
What is buffer
Old fellow teacher: F, brother, this Buffer is the sentence in our Canyon: does the old iron add Buff to me?
Of course not. This buffer is not another buffer. Buffer is the foundation of NiO. Without buffer, there will be no NiO. Without buffer, there will be no Java today.
Because NiO reads data by block, a block can be regarded as a buffer. We store the data to be read and the data to be written in the buffer to improve the efficiency of reading and writing through the buffer.
More highlights:
Remember what is the underlying storage unit of Java objects?
Younger martial sister: Well, I know that the underlying storage unit of Java objects is byte.
Yes, let's look at the inheritance diagram of buffer:
Buffer is an interface. There are many implementations below it, including the most basic ByteBuffer and other buffers encapsulated by other basic types.
Younger martial sister: Senior brother F, isn't ByteBuffer enough? What other types of buffers do?
Younger martial sister, no matter how good Shanzhen is, she sometimes gets tired of eating. She occasionally needs to change radishes and cabbage. What do you think Qianlong did when he went to Jiangnan?
Although ByteBuffer is easy to use, it is the smallest unit after all. We also have basic types such as char, int, double, short, etc. for simplicity, we also make a set of buffer for them.
Buffer advanced
Younger martial sister: elder martial brother F, since buffer is a collection of these basic types, why not use combination directly? Encapsulating them into an object seems a little redundant.
Since we are in the object-oriented world, it is reasonable to use object on the surface. In essence, these encapsulated buffers contain some additional metadata information and provide some unexpected functions.
The figure above lists several key concepts in buffer, namely capacity, limit, position and mark. The essence of buffer bottom layer is array. We take ByteBuffer as an example. Its bottom layer is:
final byte[] hb;
Create buffer
Younger martial sister: elder martial brother F, is it troublesome to create so many buffers? Is there any quick way to use it?
Generally speaking, there are two methods to create a buffer: allocate and wrap.
public void createBuffer(){
IntBuffer intBuffer= IntBuffer.allocate(10);
log.info("{}",intBuffer);
log.info("{}",intBuffer.hasArray());
int[] intArray=new int[10];
IntBuffer intBuffer2= IntBuffer.wrap(intArray);
log.info("{}",intBuffer2);
IntBuffer intBuffer3= IntBuffer.wrap(intArray,2,5);
log.info("{}",intBuffer3);
intBuffer3.clear();
log.info("{}",intBuffer3);
log.info("{}",intBuffer3.hasArray());
}
Allocate can allocate a space for buffer. Wrap also allocates a space for buffer. The difference is that the array behind this space is user-defined. Wrap also supports the method of three parameters, and the latter two parameters are offset and length respectively.
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - true
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=2 lim=7 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - true
Hasarray is used to judge whether the bottom layer of the buffer is implemented by an array. You can see that whether it is wrap or allocate, the bottom layer is an array.
Direct VS non-Direct
Younger martial sister: elder martial brother F, you said two methods to create buffers, but the background of both buffers are arrays. Is there a non array buffer?
Of course, there are, but only ByteBuffer has. ByteBuffer has an allocatedirect method that can allocate a direct buffer.
Younger martial sister: what's the difference between direct and non direct?
Direct buffer means that you do not need to copy another copy of data in the user space, but operate directly in the virtual address mapping space. This is called direct. The advantage of this is fast. The disadvantage is that more resources will be used during allocation and destruction, and because the direct buffer is not in the user space, it is not governed by the garbage collection mechanism.
Therefore, direct buffer is usually used only for data with large amount of data and long life cycle.
Look at the code below:
public void createByteBuffer() throws IOException {
ByteBuffer byteBuffer= ByteBuffer.allocateDirect(10);
log.info("{}",byteBuffer);
log.info("{}",byteBuffer.hasArray());
log.info("{}",byteBuffer.isDirect());
try (RandomAccessFile aFile = new RandomAccessFile("src/main/resources/www.flydean.com","r");
FileChannel inChannel = aFile.getChannel()) {
MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY,inChannel.size());
log.info("{}",buffer);
log.info("{}",buffer.hasArray());
log.info("{}",buffer.isDirect());
}
}
In addition to allocatedirect, a direct mappedbytebuffer can also be obtained by using the map method of filechannel.
The output result of the above example:
INFO com.flydean.BufferUsage - java.nio.DirectByteBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - false
INFO com.flydean.BufferUsage - true
INFO com.flydean.BufferUsage - java.nio.DirectByteBufferR[pos=0 lim=0 cap=0]
INFO com.flydean.BufferUsage - false
INFO com.flydean.BufferUsage - true
Daily operation of buffer
Younger martial sister: Senior brother F, it seems that buffer is a little complicated. What are the operations of buffer?
There are many buffer operations. Let's explain them below.
Write data to buffer
To write data to the buffer, you can call the put method of the buffer:
public void putBuffer(){
IntBuffer intBuffer= IntBuffer.allocate(10);
intBuffer.put(1).put(2).put(3);
log.info("{}",intBuffer.array());
intBuffer.put(0,4);
log.info("{}",intBuffer.array());
}
Because the put method returns an intbuffer class, the put method of buffer can be concatenated like stream.
At the same time, we can also specify where the put is located. The above code output:
INFO com.flydean.BufferUsage - [1,3,0]
INFO com.flydean.BufferUsage - [4,0]
Read data from buffer
The get method is used to read data, but we need to call the flip method before the get method.
What is the flip method used for? As mentioned above, the buffer has a position and limit field. Position will automatically point to the next element along with the get or put method, and limit indicates how many available elements are in the buffer.
If we want to read the value of buffer, we will start from position to limit:
public void getBuffer(){
IntBuffer intBuffer= IntBuffer.allocate(10);
intBuffer.put(1).put(2).put(3);
intBuffer.flip();
while (intBuffer.hasRemaining()) {
log.info("{}",intBuffer.get());
}
intBuffer.clear();
}
You can use hasremaining to determine whether there is another element. Clear the buffer by calling clear for next use.
rewind Buffer
Rewind is very similar to flip. The difference is that rewind does not change the value of limit, but only resets position to 0.
public void rewindBuffer(){
IntBuffer intBuffer= IntBuffer.allocate(10);
intBuffer.put(1).put(2).put(3);
log.info("{}",intBuffer);
intBuffer.rewind();
log.info("{}",intBuffer);
}
The above result output:
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]
Compact Buffer
Buffer also has a compact method. As the name suggests, compact means compression, which is to assign the value of buffer from the current position to limit to the position with position 0:
public void useCompact(){
IntBuffer intBuffer= IntBuffer.allocate(10);
intBuffer.put(1).put(2).put(3);
intBuffer.flip();
log.info("{}",intBuffer);
intBuffer.get();
intBuffer.compact();
log.info("{}",intBuffer.array());
}
Above code output:
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=3 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=2 lim=10 cap=10]
INFO com.flydean.BufferUsage - [2,0]
duplicate Buffer
Finally, let's talk about copying buffer. There are three methods: duplicate, asreadonlybuffer, and slice.
Duplicate copies the position, limit and mark of the original buffer. It shares the original data with the original buffer. Therefore, the original buffer will also be modified after modifying the duplicate buffer.
If asreadonlybuffer is used, the copied buffer is not allowed to be modified.
Slice is also readonly, but it copies the part from the position of the original buffer to the limit position.
public void duplicateBuffer(){
IntBuffer intBuffer= IntBuffer.allocate(10);
intBuffer.put(1).put(2).put(3);
log.info("{}",intBuffer);
IntBuffer duplicateBuffer=intBuffer.duplicate();
log.info("{}",duplicateBuffer);
IntBuffer readOnlyBuffer=intBuffer.asReadOnlyBuffer();
log.info("{}",readOnlyBuffer);
IntBuffer sliceBuffer=intBuffer.slice();
log.info("{}",sliceBuffer);
}
Output results:
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBufferR[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=7 cap=7]