Saturday, April 22, 2023

ByteBuffer Read Write Example in Java

Hello guys, if you have worked with Java NIO API then there is a good chance that you may be familiar with ByteBuffer, one of the important class which is used to read and write data from channels. Java NIO Buffers are used when interacting with NIO Channels like FileChannel. As you know, data is read from channels into buffers, and written from buffers into channels. A buffer is essentially a block of memory into which you can write data, which you can then later read again. This memory block is wrapped in an NIO Buffer object, which provides a set of methods that makes it easier to work with the memory block. If you compare this with traditional java.io package then you will remember that we read and write data from stream into array but in case of NIO, we read and write data from channels into ByteBuffer

If you are wondering how to read and write data from Buffer then don't worry in this article I will show you how to do that. One of the key thing to remember is that when you read data from a ByteBuffer, where you have written data, you first need to flip the buffer. That's an important step which many Java Programmer forget.

Also, there are two types of ByteBuffer direct and in-direct byte buffer, In case of direct byte buffer JVM will make best effort to perform native IO operation directly upon the buffer while in case of in-direct buffer it will use JDK API. 

If you want to learn more about direct and non-direct buffer, then I also suggest you to checkout my earlier post about difference between direct, mapped and non-direct buffer in Java. 



Java Program to read and write data from ByteBuffer

Here is our complete Java program to demonstrate how to read data from buffer and how to write data into ByteBuffer using allocateDirect() and allocate() method in Java.  When you use allocateDirect() method then a DirectByteBuffer is created where JVM can perform native read and write operation.  Both allocate() and allocateDirect() takes one parameter, the capacity of the buffer. 

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
 
/**
*
* Java Program to read and write from ByteBuffer.
* You can create direct buffer or on heap ByteBuffer 
* using allocateDirect() and allocate() method.
*
* @author Javin
*/
public class ByteBufferDemo {
 
    public static void main(String args[]) {
 
        // Creates and initialize ByteBuffer in Java
        ByteBuffer buffer = ByteBuffer.allocate(1024);
 
        System.out.printf("new buffer, position : %s, limit : %s,
                                         and capacity : %s %n",
        buffer.position(), buffer.limit(), buffer.capacity());
 
        System.out.println("writing integer, long and double into byte buffer");
        buffer.putInt(20); // 4 bytes written
        buffer.putLong(400000032); // 8 bytes written
        buffer.putDouble(21.3); // 8 bytes written
 
        System.out.printf("After writing, position : %s, limit : %s,
                                        and capacity : %s %n",
                buffer.position(), buffer.limit(), buffer.capacity());
 
        // flip the buffer to read data
        buffer.flip();
 
        System.out.printf("After flip, position : %s, limit : %s,
                                        and capacity : %s %n",
                buffer.position(), buffer.limit(), buffer.capacity());
 
        System.out.println("Reading integer from ByteBuffer in Java : " 
                                + buffer.getInt());
        System.out.println("Reading long from ByteBuffer in Java : " 
                                + buffer.getLong());
        System.out.println("Reading double from ByteBuffer in Java : " 
                                + buffer.getDouble());
 
        // you can clear buffer for reuse
        buffer.clear();
 
        System.out.printf("After clearing ByteBuffer, position : %s, 
                         limit : %s, and capacity : %s %n",
                buffer.position(), buffer.limit(), buffer.capacity());
 
    }
 
}
 
Output
new buffer, position : 0, limit : 1024, and capacity : 1024
writing integer, long and double into byte buffer
After writing, position : 20, limit : 1024, and capacity : 1024
After flip, position : 0, limit : 20, and capacity : 1024
Reading integer from ByteBuffer in Java : 20
Reading long from ByteBuffer in Java : 400000032
Reading double from ByteBuffer in Java : 21.3
After clearing ByteBuffer, position : 0, limit : 1024, and capacity : 1024


You can see that when we first created ByteBuffer using allocate() method it accept one single parameter which is capacity of the buffer. After creating, you can also see  that position points to 0 while both limit and capacity variable points to 1024, the actual limit of buffer we provided when we created it.

When you start writing data into ByteBuffer, you can see that position gradually start shifting to empty location but both limit and capacity remains same and still point to the maximum index where data can be written.

When we done with writing and flip the buffer to read data from it, you can see that position variable reset to 0 and limit points to the last position value in write mode but capacity remains same. 

Here is a nice diagram which nicely explains the reading and writing data into Buffer, you can see that in write mode both limit and capacity points to same location but in case of read mode, limit actually points until data is written.

ByteBuffer Read Write Example in Java



Important points to know about ByteBuffer in Java

1. There is no put() method to write boolean type into ByteBuffer in Java. So you can either use 0 or 1 to represent boolean true and false or can use "Y" and "N". You can store these by using putChar() or put() method

2. ByteBuffers are Not safe for use by multiple concurrent threads

3. When I/O operation is initiated then must take great care not to access buffer until I/O operation completes

4. Memory requirements for buffers depend on the number of outstanding I/O operations

5. Heap buffers incur additional copy per I/O As per SocketChannel API, compare the performance

6. Copy performance and temporary direct buffer usage improved


That's all about how to use ByteBuffer in Java. In this Java NIO tutorial, you have learned how to read, write and work with ByteBuffer in Java. This is one of the core class to work with Bytes and NIO classes like FileChannels and ServerSockets. I highly recommend every Java developer to learn about ByteBuffer, its an essential concept but its not that intuitive, especially how to read and write on Buffer because you need to flip the buffer, which confuses many programmer and causes issues. 

Other Java IO and NIO tutorials you may like:

Thanks for reading this article so far. If you like this ByteBuffer tutorial in Java then please share it with your friends and colleagues. If you have any questions or feedback then please drop a note.

No comments:

Post a Comment