o7planning

Java ReadableByteChannel Tutorial with Examples

  1. ReadableByteChannel
  2. Methods
  3. read(ByteBuffer)
  4. Example 1
  5. Example 2

1. ReadableByteChannel

If you are just getting started with Java NIO, read the following articles first to understand more about the basics:
  • Java Nio
ReadableByteChannel is an interface that extends from the Channel interface, which represents channels that can read bytes from an IO device.
public interface ReadableByteChannel extends Channel
ReadableByteChannel provides only one method, which is used to read bytes into a ByteBuffer. You can call this method multiple times to read all the data from the Channel.
public int read(ByteBuffer dst) throws IOException;
Only one read operation on the Channel can take place at a time. This means that if one thread is initiating a read operation on a Channel, other threads cannot read on this Channel, they are blocked until the operation is completed. Other IO operations can be performed concurrently with the read operation depending on the Channel type.
Hierarchy of interfaces and classes related to ReadableByteChannel:

2. Methods

ReadableByteChannel provides only one more method compared to its parent interface.
public int read(ByteBuffer dst) throws IOException;
Other methods inherited from the Channel interface:
public boolean isOpen();  
public void close() throws IOException;

3. read(ByteBuffer)

public int read(ByteBuffer byteBuffer) throws IOException;
The read(ByteBuffer) method reads a sequence of bytes from this ReadableByteChannel and assigns the elements between position and limit-1 on the ByteBuffer. It will read as much as possible and return the number of bytes read. Returns -1 if the end of the channel has been reached.
  • Each byte assigned to the ByteBuffer will increase the cursor position by 1.
  • Before calling this method you should call ByteBuffer.clear() method to set position = 0 and limit = capacity.
  • The maximum number of bytes that can be read in one call of this method is byteBuffer.limit()-byteBuffer.position().
Only one read operation on the Channel can take place at a time. This means that if one thread is initiating a read operation on a Channel, other threads cannot read on this Channel, they are blocked until the operation is completed. Other IO operations can be performed concurrently with the read operation depending on the Channel type.

4. Example 1

Example: Use ReadableByteChannel to read data from an InputStream, specifically from a ByteArrayInputStream.
Below is an image of the bytes of the string "JP日本-八洲" in UTF-8 format (UTF-8 uses 1, 2, 3 or 4 bytes to store a character).
ReadableByteChannel_ex1.java
package org.o7planning.readablebytechannel.ex;

import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

public class ReadableByteChannel_ex1 {

    public static void main(String[] args) throws IOException {
        InputStream inputStream = null;
        ReadableByteChannel channel = null;
        try {
            byte[] byteData = "JP日本-八洲".getBytes("UTF-8");
            inputStream = new ByteArrayInputStream(byteData);
            
            // Create ReadableByteChannel to read a InputStream.
            channel = Channels.newChannel(inputStream);
            ByteBuffer buffer = ByteBuffer.allocate(10);

            int bytesRead = -1;
            while ((bytesRead = channel.read(buffer)) > -1) {
                System.out.println(" --- bytesRead : " + bytesRead + " ---- ");
                // Set limit = current position; position = 0;
                buffer.flip();

                while (buffer.hasRemaining()) {
                    byte b = buffer.get(); // [-128,127]
                    int charCode = Byte.toUnsignedInt(b); // [0,255] Java 8+
                    System.out.println((char) charCode + " --> " + charCode);
                }
                // Set position = 0; limit = capacity.
                buffer.clear();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeQuietly(inputStream);
            closeQuietly(channel);
        }
    }

    private static void closeQuietly(Closeable closeable) {
        try {
            closeable.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Output:
--- bytesRead : 10 ----
J --> 74
P --> 80
æ --> 230
— --> 151
¥ --> 165
æ --> 230
œ --> 156
¬ --> 172
- --> 45
å --> 229
 --- bytesRead : 5 ----
… --> 133
« --> 171
æ --> 230
´ --> 180
² --> 178
Both InputStream and Channel implement or extend from the Closeable interface, so it has the ability to automatically close if you use the "Closeable-try-catch" syntax. And we rewrite the above example more succinctly.
ReadableByteChannel_ex1b.java
package org.o7planning.readablebytechannel.ex;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

public class ReadableByteChannel_ex1b {

    public static void main(String[] args) throws IOException {
        byte[] byteData = "JP日本-八洲".getBytes("UTF-8");

        // Closeable-try-catch Syntax:
        try (InputStream inputStream = new ByteArrayInputStream(byteData);
                // Create ReadableByteChannel to read a InputStream.
                ReadableByteChannel channel = Channels.newChannel(inputStream);) { // try
            ByteBuffer buffer = ByteBuffer.allocate(10);

            int bytesRead = -1;
            while ((bytesRead = channel.read(buffer)) > -1) {
                System.out.println(" --- bytesRead : " + bytesRead + " ---- ");
                // Set limit = current position; position = 0;
                buffer.flip();

                while (buffer.hasRemaining()) {
                    byte b = buffer.get(); // [-128,127]
                    int charCode = Byte.toUnsignedInt(b); // [0,255] Java 8+
                    System.out.println((char) charCode + " --> " + charCode);
                }
                // Set position = 0; limit = capacity.
                buffer.clear();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5. Example 2

Example: Read a data file on the network.
ReadableByteChannel_ex2.java
String urlString = "https://s3.o7planning.com/txt/utf8-file-without-bom.txt";
URL url = new URL(urlString);

try (InputStream inputStream = url.openStream();
        // Create ReadableByteChannel to read a InputStream.
        ReadableByteChannel channel = Channels.newChannel(inputStream);) { // try
    
    ByteBuffer buffer = ByteBuffer.allocate(10);
    int bytesRead = -1;
    while ((bytesRead = channel.read(buffer)) > -1) {
        System.out.println(" --- bytesRead : " + bytesRead + " ---- ");
        // Set limit = current position; position = 0;
        buffer.flip();

        while (buffer.hasRemaining()) {
            byte b = buffer.get(); // [-128,127]
            int charCode = Byte.toUnsignedInt(b); // [0,255] Java 8+
            System.out.println((char) charCode + " --> " + charCode);
        }
        // Set position = 0; limit = capacity.
        buffer.clear();
    }
} catch (Exception e) {
    e.printStackTrace();
}
Output:
--- bytesRead : 10 ----
J --> 74
P --> 80
æ --> 230
— --> 151
¥ --> 165
æ --> 230
œ --> 156
¬ --> 172
- --> 45
å --> 229
 --- bytesRead : 5 ----
… --> 133
« --> 171
æ --> 230
´ --> 180
² --> 178