betacode

Руководство Java ReadableByteChannel

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

1. ReadableByteChannel

Если вы только начинаете работать с Java NIO, сначала прочитайте следующие статьи, чтобы узнать больше об основах:
  • Java Nio
ReadableByteChannel - это интерфейс, который расширяется от interface Channel, представляющего каналы, которые могут считывать bytes с устройства IO.
public interface ReadableByteChannel extends Channel
ReadableByteChannel предоставляет только один метод, который используется для считывания bytes в ByteBuffer. Вы можете вызвать этот метод несколько раз, чтобы прочитать все данные из Channel.
public int read(ByteBuffer dst) throws IOException;
Одновременно может выполняться только одна операция чтения на Channel. Это означает, что если один thread инициирует операцию чтения на Channel, другие thread не могут читать на этом Channel, они блокируются (block) до завершения операции. Другие операции IO могут выполняться одновременно с операцией чтения в зависимости от типа Channel.
Иерархия интерфейсов и классов, связанных с ReadableByteChannel:

2. Methods

ReadableByteChannel предоставляет только один дополнительный метод по сравнению со своим родительским интерфейсом.
public int read(ByteBuffer dst) throws IOException;
Другие методы, унаследованные от интерфейса Channel:
public boolean isOpen();  
public void close() throws IOException;

3. read(ByteBuffer)

public int read(ByteBuffer byteBuffer) throws IOException;
Метод read(ByteBuffer) считывает последовательность bytes из этого ReadableByteChannel и присваивает элементам между position и limit-1 в ByteBuffer. Он прочитает как можно больше и возвращает количество прочитанных bytes. Возвращает -1, если достигнут конец канала.
  • Каждый byte, назначенный ByteBuffer, увеличит положение курсора на 1.
  • Перед вызовом этого метода вы должны вызвать метод ByteBuffer.clear(), чтобы установить position = 0 и limit = capacity.
  • Максимальное количество bytes, которое может быть прочитано за один вызов этого метода, равно byteBuffer.limit()-byteBuffer.position().
Одновременно может выполняться только одна операция чтения на Channel. Это означает, что если один thread инициирует операцию чтения на Channel, другие thread не могут читать на этом Channel, они блокируются (block) до завершения операции. Другие операции IO могут выполняться одновременно с операцией чтения в зависимости от типа Channel.

4. Example 1

Например: Используйте ReadableByteChannel для чтения данных из InputStream, в частности из ByteArrayInputStream.
Ниже приведено изображение bytes строки "JP日本-八洲" в формате UTF-8 (UTF-8 использует 1, 2, 3 или 4 bytes для хранения символа).
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
Как InputStream, так и Channel реализуют (implements) или расширяются из interface Closeable, поэтому он может автоматически закрываться, если вы используете синтаксис "Closeable-try-catch". И мы перепишем приведенный выше пример более сжато.
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

Например: Прочитайте файл данных в сети.
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