Перейти к контенту

Java NIO AsynchronousFileChannel

В Java 7 AsynchronousFileChannel был добавлен в Java NIO. AsynchronousFileChannel позволяет считывать данные и записывать данные в файлы асинхронно.

Создание AsynchronousFileChannel

Вы создаете AsynchronousFileChannel через его статический метод open(). Вот пример создания AsynchronousFileChannel:

 

Path path = Paths.get("data/test.xml");

AsynchronousFileChannel fileChannel =
    AsynchronousFileChannel.open(path, StandardOpenOption.READ);

Первым параметром метода open() является экземпляр Path, указывающий на файл, с которым должен быть связан AsynchronousFileChannel.

Второй параметр — это одна или несколько открытых опций, которые сообщают AsynchronousFileChannel, какие операции необходимо выполнить с базовым файлом. В этом примере мы использовали StandardOpenOption.READ, что означает, что файл будет открыт для чтения.

Чтение данных

Вы можете прочитать данные из AsynchronousFileChannel двумя способами. Каждый способ чтения данных вызывает один из методов read() класса AsynchronousFileChannel. Оба метода чтения данных будут рассмотрены в следующих разделах.

Чтение данных через Future

Первый способ чтения данных из AsynchronousFileChannel — это вызов метода read(), который возвращает Future. Вот как выглядит вызов метода read():

Future operation = fileChannel.read(buffer, 0);

Эта версия метода read() принимает ByteBuffer в качестве первого параметра. Данные, считанные из AsynchronousFileChannel, считываются в этот ByteBuffer. Второй параметр — это позиция байта в файле, с которой начинается чтение.

Метод read() возвращает результат немедленно, даже если операция чтения не завершена. Вы можете проверить, когда операция чтения завершена, вызвав метод isDone() экземпляра Future, возвращенного методом read().

Вот более длинный пример, показывающий, как использовать эту версию метода read():

AsynchronousFileChannel fileChannel = 
    AsynchronousFileChannel.open(path, StandardOpenOption.READ);

ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0;

Future operation = fileChannel.read(buffer, position);

while(!operation.isDone());

buffer.flip();
byte[] data = new byte[buffer.limit()];
buffer.get(data);
System.out.println(new String(data));
buffer.clear();

В этом примере создается AsynchronousFileChannel, а затем создается ByteBuffer, который передается методу read() в качестве параметра вместе с позицией 0. После вызова read() пример зацикливается, пока метод isDone() возвращаемого Future не вернет true. Конечно, это не очень эффективное использование процессора — но как-то нужно подождать, пока операция чтения не завершится.

После завершения операции чтения данные считываются в ByteBuffer, а затем в String и печатаются в System.out.

Чтение данных через CompletionHandler

Второй метод чтения данных из AsynchronousFileChannel — это вызов версии метода read(), которая принимает CompletionHandler в качестве параметра. Вот как вы вызываете этот метод read():

fileChannel.read(buffer, position, buffer, new CompletionHandler() {
    @Override
    public void completed(Integer result, ByteBuffer attachment) {
        System.out.println("result = " + result);

        attachment.flip();
        byte[] data = new byte[attachment.limit()];
        attachment.get(data);
        System.out.println(new String(data));
        attachment.clear();
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {

    }
});

Как только операция чтения завершится, будет вызван метод complete() CompletionHandler. В качестве параметров к завершенному методу() передается целое число, указывающее, сколько байтов было прочитано, и «вложение», которое было передано методу read(). «Вложение» — это третий параметр метода read(). В данном случае это был ByteBuffer, в который также считываются данные. Вы можете свободно выбирать, какой объект прикрепить.

Если операция чтения завершится неудачно, вместо этого будет вызван метод failed() класса CompletionHandler.

Запись данных

Как и при чтении, вы можете записывать данные в AsynchronousFileChannel двумя способами. Каждый способ записи данных вызывает один из методов write() класса AsynchronousFileChannel. Оба метода записи данных будут рассмотрены в следующих разделах.

Запись данных через Future

AsynchronousFileChannel также позволяет записывать данные асинхронно. Вот полный пример записи Java AsynchronousFileChannel:

Path path = Paths.get("data/test-write.txt");
AsynchronousFileChannel fileChannel = 
    AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);

ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0;

buffer.put("test data".getBytes());
buffer.flip();

Future operation = fileChannel.write(buffer, position);
buffer.clear();

while(!operation.isDone());

System.out.println("Write done");

Сначала AsynchronousFileChannel открывается в режиме записи. Затем создается ByteBuffer и некоторые данные записываются в него. Затем данные в ByteBuffer записываются в файл. Наконец, пример проверяет возвращенное Future, чтобы увидеть, когда операция записи завершена.

Обратите внимание, что файл должен уже существовать, прежде чем этот код будет работать. Если файл не существует, метод write() сгенерирует исключение java.nio.file.NoSuchFileException.

Вы можете убедиться, что файл, на который указывает путь, существует с помощью следующего кода:

if(!Files.exists(path)){
    Files.createFile(path);
}

Запись через CompletionHandler

Вы также можете записать данные в AsynchronousFileChannel с помощью CompletionHandler, чтобы сообщить вам, когда запись завершена, а не в будущем. Вот пример записи данных в AsynchronousFileChannel с помощью CompletionHandler:

Path path = Paths.get("data/test-write.txt");
if(!Files.exists(path)){
    Files.createFile(path);
}
AsynchronousFileChannel fileChannel = 
    AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);

ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0;

buffer.put("test data".getBytes());
buffer.flip();

fileChannel.write(buffer, position, buffer, new CompletionHandler() {

    @Override
    public void completed(Integer result, ByteBuffer attachment) {
        System.out.println("bytes written: " + result);
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {
        System.out.println("Write failed");
        exc.printStackTrace();
    }
});

Завершение метода CompletionHandler() будет вызвано после завершения операции записи. Если по какой-либо причине запись не удалась, вместо нее будет вызван метод failed().

Обратите внимание, как ByteBuffer используется в качестве вложения — объекта, который передается методам CompletionHandler.

Оцени статью

Средняя оценка / 5. Количество голосов:

Спасибо, помогите другим - напишите комментарий, добавьте информации к статье.

Или поделись статьей

Видим, что вы не нашли ответ на свой вопрос.

Помогите улучшить статью.

 

Пока нет комментариев.

Добавить комментарий

Ваш e-mail не будет опубликован.

СайдбарКомментарии (0)