Учебники

Java NIO — Краткое руководство

Java NIO — Обзор

Пакет Java.nio был представлен в Java 1.4. В отличие от java I / O в java NIO введен поток данных, ориентированный на буфер и канал, для операций ввода / вывода, что в результате обеспечивает более быстрое выполнение и лучшую производительность.

Также NIO API предлагает селекторы, которые вводят функциональность прослушивания нескольких каналов для событий ввода-вывода асинхронным или неблокирующим способом. В NIO наиболее трудоемкие операции ввода-вывода, включая заполнение и опустошение буферов для операционной системы, которые увеличиваются в скорости.

Основные абстракции API-интерфейсов NIO следующие —

  • Буферы, которые являются контейнерами для данных, наборов символов и связанных с ними декодеров и кодеров, которые преобразуются между байтами и символами Unicode.

  • Каналы различных типов, которые представляют соединения с объектами, способными выполнять операции ввода-вывода

  • Селекторы и клавиши выбора, которые вместе с выбираемыми каналами определяют мультиплексированный неблокирующий механизм ввода / вывода.

Буферы, которые являются контейнерами для данных, наборов символов и связанных с ними декодеров и кодеров, которые преобразуются между байтами и символами Unicode.

Каналы различных типов, которые представляют соединения с объектами, способными выполнять операции ввода-вывода

Селекторы и клавиши выбора, которые вместе с выбираемыми каналами определяют мультиплексированный неблокирующий механизм ввода / вывода.

Java NIO — настройка среды

В этом разделе рассказывается, как загрузить и настроить Java на вашем компьютере. Пожалуйста, выполните следующие шаги для настройки среды.

Java SE находится в свободном доступе по ссылке Скачать Java . Таким образом, вы загружаете версию, основанную на вашей операционной системе.

Следуйте инструкциям для загрузки Java и запуска .exe для установки Java на вашем компьютере. После того, как вы установили Java на свой компьютер, вам нужно будет установить переменные окружения, чтобы они указывали на правильные каталоги установки —

Настройка пути для Windows 2000 / XP

Предполагая, что вы установили Java в каталог c: \ Program Files \ java \ jdk

  • Щелкните правой кнопкой мыши «Мой компьютер» и выберите «Свойства».

  • Нажмите кнопку «Переменные среды» на вкладке «Дополнительно».

  • Теперь измените переменную Path, чтобы она также содержала путь к исполняемому файлу Java. Например, если в настоящий момент путь задан как «C: \ WINDOWS \ SYSTEM32», измените ваш путь на «C: \ WINDOWS \ SYSTEM32; c: \ Program Files \ java \ jdk \ bin».

Щелкните правой кнопкой мыши «Мой компьютер» и выберите «Свойства».

Нажмите кнопку «Переменные среды» на вкладке «Дополнительно».

Теперь измените переменную Path, чтобы она также содержала путь к исполняемому файлу Java. Например, если в настоящий момент путь задан как «C: \ WINDOWS \ SYSTEM32», измените ваш путь на «C: \ WINDOWS \ SYSTEM32; c: \ Program Files \ java \ jdk \ bin».

Настройка пути для Windows 95/98 / ME

Предполагая, что вы установили Java в каталог c: \ Program Files \ java \ jdk

  • Отредактируйте файл ‘C: \ autoexec.bat’ и добавьте следующую строку в конце:
    ‘SET PATH =% PATH%; C: \ Program Files \ java \ jdk \ bin’

Отредактируйте файл ‘C: \ autoexec.bat’ и добавьте следующую строку в конце:
‘SET PATH =% PATH%; C: \ Program Files \ java \ jdk \ bin’

Настройка пути для Linux, UNIX, Solaris, FreeBSD

Переменная среды PATH должна быть указана в том месте, где были установлены двоичные файлы Java. Обратитесь к документации по вашей оболочке, если у вас возникли проблемы с этим.

Например, если вы используете bash в качестве оболочки, вы добавили бы следующую строку в конец вашего .bashrc: export PATH = / path / to / java: $ PATH ‘

Популярные редакторы Java

Для написания ваших Java-программ вам понадобится текстовый редактор. На рынке доступны еще более сложные IDE. Но сейчас вы можете рассмотреть один из следующих —

  • Блокнот — на компьютере с Windows вы можете использовать любой простой текстовый редактор, например Блокнот (рекомендуется для этого урока), TextPad.

  • Netbeans — это Java IDE с открытым исходным кодом, который можно бесплатно загрузить по адресу http://www.netbeans.org/index.html .

  • Eclipse — это также Java IDE, разработанная сообществом открытого исходного кода eclipse, которую можно скачать по адресу https://www.eclipse.org/ .

Блокнот — на компьютере с Windows вы можете использовать любой простой текстовый редактор, например Блокнот (рекомендуется для этого урока), TextPad.

Netbeans — это Java IDE с открытым исходным кодом, который можно бесплатно загрузить по адресу http://www.netbeans.org/index.html .

Eclipse — это также Java IDE, разработанная сообществом открытого исходного кода eclipse, которую можно скачать по адресу https://www.eclipse.org/ .

Java NIO против IO

Как мы знаем, Java NIO введен для усовершенствования традиционного API Java IO. Основными усовершенствованиями, которые делают NIO более эффективным, чем IO, являются модель потока данных канала, используемая в NIO, и использование операционной системы для обычных задач ввода-вывода.

Разницу между Java NIO и Java IO можно объяснить следующим образом:

  • Как упоминалось в предыдущем посте, в буфере NIO и канально-ориентированном потоке данных для операций ввода / вывода, которые обеспечивают более быстрое выполнение и лучшую производительность по сравнению с IO. Также NIO использует операционную систему для обычных задач ввода / вывода, что снова делает ее более эффективной.

  • Другой аспект различия между NIO и IO состоит в том, что этот IO использует поток данных линии потока, то есть еще один байт за раз, и полагается на преобразование объектов данных в байты и наоборот, в то время как NIO работает с блоками данных, которые являются кусками байтов.

  • В Java потоковые объекты ввода / вывода являются однонаправленными, в то время как в NIO каналы являются двунаправленными, то есть канал может использоваться как для чтения, так и для записи данных.

  • Потоковый поток данных в IO не позволяет перемещаться вперед и назад в данных. В случае необходимости перемещаться вперед и назад в данных, считанных из потока, необходимо сначала кэшировать их в буфере. В случае NIO мы используем ориентированный на буфер что позволяет получать доступ к данным взад и вперед без необходимости кэширования.

  • NIO API также поддерживает многопоточность, так что данные могут считываться и записываться асинхронно, таким образом, чтобы при выполнении операций ввода-вывода текущий поток не блокировался. Это снова делает его более эффективным, чем обычный API ввода-вывода Java.

  • Концепция многопоточности вводится с введением селекторов в Java NIO, которые позволяют прослушивать несколько каналов для событий ввода-вывода асинхронным или неблокирующим способом.

  • Многопоточность в NIO делает его неблокирующим, что означает, что поток запрашивается для чтения или записи только при наличии данных, в противном случае поток можно использовать в другой задаче на время. Но это невозможно в случае обычного ввода-вывода Java, так как нет многопоточности поддерживается в нем, что делает его как блокирующий.

  • NIO позволяет управлять несколькими каналами, используя только один поток, но стоимость состоит в том, что синтаксический анализ данных может быть несколько более сложным, чем при чтении данных из блокирующего потока в случае Java-ввода-вывода. Так что в случае, если требуется меньше соединений с очень высокой пропускной способностью с отправкой большого количества данных за один раз, тогда в этом случае лучше всего подойдет java IO API.

Как упоминалось в предыдущем посте, в буфере NIO и канально-ориентированном потоке данных для операций ввода / вывода, которые обеспечивают более быстрое выполнение и лучшую производительность по сравнению с IO. Также NIO использует операционную систему для обычных задач ввода / вывода, что снова делает ее более эффективной.

Другой аспект различия между NIO и IO состоит в том, что этот IO использует поток данных линии потока, то есть еще один байт за раз, и полагается на преобразование объектов данных в байты и наоборот, в то время как NIO работает с блоками данных, которые являются кусками байтов.

В Java потоковые объекты ввода / вывода являются однонаправленными, в то время как в NIO каналы являются двунаправленными, то есть канал может использоваться как для чтения, так и для записи данных.

Потоковый поток данных в IO не позволяет перемещаться вперед и назад в данных. В случае необходимости перемещаться вперед и назад в данных, считанных из потока, необходимо сначала кэшировать их в буфере. В случае NIO мы используем ориентированный на буфер что позволяет получать доступ к данным взад и вперед без необходимости кэширования.

NIO API также поддерживает многопоточность, так что данные могут считываться и записываться асинхронно, таким образом, чтобы при выполнении операций ввода-вывода текущий поток не блокировался. Это снова делает его более эффективным, чем обычный API ввода-вывода Java.

Концепция многопоточности вводится с введением селекторов в Java NIO, которые позволяют прослушивать несколько каналов для событий ввода-вывода асинхронным или неблокирующим способом.

Многопоточность в NIO делает его неблокирующим, что означает, что поток запрашивается для чтения или записи только при наличии данных, в противном случае поток можно использовать в другой задаче на время. Но это невозможно в случае обычного ввода-вывода Java, так как нет многопоточности поддерживается в нем, что делает его как блокирующий.

NIO позволяет управлять несколькими каналами, используя только один поток, но стоимость состоит в том, что синтаксический анализ данных может быть несколько более сложным, чем при чтении данных из блокирующего потока в случае Java-ввода-вывода. Так что в случае, если требуется меньше соединений с очень высокой пропускной способностью с отправкой большого количества данных за один раз, тогда в этом случае лучше всего подойдет java IO API.

Java NIO — Каналы

Описание

Как следует из названия, канал используется как среднее значение потока данных от одного конца к другому. Здесь в канале Java NIO действуют одинаково между буфером и объектом на другом конце, другими словами, канал используется для чтения данных в буфер, а также для записи данных из буфера.

В отличие от потоков, которые используются в традиционных каналах Java IO, они являются двухсторонними, т.е. могут считывать и записывать. Канал Java NIO поддерживает асинхронный поток данных как в режиме блокировки, так и в режиме без блокировки.

Реализации канала

Канал Java NIO реализован в основном в следующих классах —

  • FileChannel — Для чтения данных из файла мы используем файловый канал. Объект файлового канала может быть создан только путем вызова метода getChannel () для файлового объекта, поскольку мы не можем напрямую создать файловый объект.

  • DatagramChannel — канал дейтаграмм может считывать и записывать данные по сети через UDP (протокол пользовательских дейтаграмм). Объект DataGramchannel может быть создан с использованием заводских методов.

  • SocketChannel — канал SocketChannel может считывать и записывать данные по сети через TCP (протокол управления передачей). Он также использует фабричные методы для создания нового объекта.

  • ServerSocketChannel — ServerSocketChannel для чтения и записи данных через TCP-соединения, так же, как веб-сервер. Для каждого входящего соединения создается SocketChannel.

FileChannel — Для чтения данных из файла мы используем файловый канал. Объект файлового канала может быть создан только путем вызова метода getChannel () для файлового объекта, поскольку мы не можем напрямую создать файловый объект.

DatagramChannel — канал дейтаграмм может считывать и записывать данные по сети через UDP (протокол пользовательских дейтаграмм). Объект DataGramchannel может быть создан с использованием заводских методов.

SocketChannel — канал SocketChannel может считывать и записывать данные по сети через TCP (протокол управления передачей). Он также использует фабричные методы для создания нового объекта.

ServerSocketChannel — ServerSocketChannel для чтения и записи данных через TCP-соединения, так же, как веб-сервер. Для каждого входящего соединения создается SocketChannel.

пример

Следующий пример читает из текстового файла из C: /Test/temp.txt и печатает содержимое на консоль.

temp.txt

Hello World!

ChannelDemo.java

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ChannelDemo {
   public static void main(String args[]) throws IOException {
      RandomAccessFile file = new RandomAccessFile("C:/Test/temp.txt", "r");
      FileChannel fileChannel = file.getChannel();
      ByteBuffer byteBuffer = ByteBuffer.allocate(512);
      while (fileChannel.read(byteBuffer) > 0) {
         // flip the buffer to prepare for get operation
         byteBuffer.flip();
         while (byteBuffer.hasRemaining()) {
            System.out.print((char) byteBuffer.get());
         }
      }
      file.close();
   }
}

Выход

Hello World!

Java NIO — Файловый канал

Описание

Как уже упоминалось, в FileChannel реализована реализация канала Java NIO для доступа к свойствам метаданных файла, включая создание, изменение, размер и т. Д. Наряду с этим каналы являются многопоточными, что снова делает Java NIO более эффективным, чем Java IO.

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

Мы не можем получить объект файлового канала напрямую, объект файлового канала получается либо —

  • getChannel () — метод для любого FileInputStream, FileOutputStream или RandomAccessFile.

  • open () — метод File channel, который по умолчанию открывает канал.

getChannel () — метод для любого FileInputStream, FileOutputStream или RandomAccessFile.

open () — метод File channel, который по умолчанию открывает канал.

Тип объекта канала File зависит от типа класса, вызываемого при создании объекта, т. Е. Если объект создается путем вызова метода getchannel из FileInputStream, то канал File открывается для чтения и выдает исключение NonWritableChannelException в случае попытки записи в него.

пример

В следующем примере показано, как читать и записывать данные из Java NIO FileChannel.

Следующий пример читает из текстового файла из C: /Test/temp.txt и печатает содержимое на консоль.

temp.txt

Hello World!

FileChannelDemo.java

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashSet;
import java.util.Set;

public class FileChannelDemo {
   public static void main(String args[]) throws IOException {
      //append the content to existing file 
      writeFileChannel(ByteBuffer.wrap("Welcome to TutorialsPoint".getBytes()));
      //read the file
      readFileChannel();
   }
   public static void readFileChannel() throws IOException {
      RandomAccessFile randomAccessFile = new RandomAccessFile("C:/Test/temp.txt",
      "rw");
      FileChannel fileChannel = randomAccessFile.getChannel();
      ByteBuffer byteBuffer = ByteBuffer.allocate(512);
      Charset charset = Charset.forName("US-ASCII");
      while (fileChannel.read(byteBuffer) > 0) {
         byteBuffer.rewind();
         System.out.print(charset.decode(byteBuffer));
         byteBuffer.flip();
      }
      fileChannel.close();
      randomAccessFile.close();
   }
   public static void writeFileChannel(ByteBuffer byteBuffer)throws IOException {
      Set<StandardOpenOption> options = new HashSet<>();
      options.add(StandardOpenOption.CREATE);
      options.add(StandardOpenOption.APPEND);
      Path path = Paths.get("C:/Test/temp.txt");
      FileChannel fileChannel = FileChannel.open(path, options);
      fileChannel.write(byteBuffer);
      fileChannel.close();
   }
}

Выход

Hello World! Welcome to TutorialsPoint

Java NIO — канал дейтаграмм

Java NIO дейтаграмма используется в качестве канала, который может отправлять и получать UDP-пакеты по протоколу без установления соединения. По умолчанию канал дейтаграмм блокируется, и его можно использовать в неблокирующем режиме. Чтобы сделать его неблокирующим, мы можем использовать configureBlocking ( false) метод. Канал DataGram можно открыть, вызвав его один из статических методов с именем open (), который также может принимать IP-адрес в качестве параметра, чтобы его можно было использовать для многоадресной передачи.

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

Мы можем проверить состояние соединения канала дейтаграмм, вызвав его метод isConnected (). После подключения канал дейтаграмм остается подключенным до тех пор, пока он не будет отключен или закрыт. Каналы дейтаграмм являются поточно-ориентированными и поддерживают многопоточность и параллелизм одновременно.

Важные методы дейтаграммы канала

  • bind (SocketAddress local) — этот метод используется для привязки сокета канала дейтаграммы к локальному адресу, который предоставляется в качестве параметра для этого метода.

  • connect (SocketAddress remote) — этот метод используется для подключения сокета к удаленному адресу.

  • disconnect () — этот метод используется для отключения сокета от удаленного адреса.

  • getRemoteAddress () — Этот метод возвращает адрес удаленного местоположения, к которому подключен сокет канала.

  • isConnected () — как уже упоминалось, этот метод возвращает статус подключения канала дейтаграммы, т. е. подключен он или нет.

  • open () и open (семейство ProtocolFamily) — используется метод Open, который открывает канал дейтаграммы для одного адреса, в то время как параметризованный метод Open метод открытия канала для нескольких адресов, представленных в виде семейства протоколов.

  • read (ByteBuffer dst) — этот метод используется для чтения данных из данного буфера через канал дейтаграммы.

  • receive (ByteBuffer dst) — этот метод используется для получения дейтаграммы через этот канал.

  • send (ByteBuffer src, SocketAddress target) — этот метод используется для отправки дейтаграммы по этому каналу.

bind (SocketAddress local) — этот метод используется для привязки сокета канала дейтаграммы к локальному адресу, который предоставляется в качестве параметра для этого метода.

connect (SocketAddress remote) — этот метод используется для подключения сокета к удаленному адресу.

disconnect () — этот метод используется для отключения сокета от удаленного адреса.

getRemoteAddress () — Этот метод возвращает адрес удаленного местоположения, к которому подключен сокет канала.

isConnected () — как уже упоминалось, этот метод возвращает статус подключения канала дейтаграммы, т. е. подключен он или нет.

open () и open (семейство ProtocolFamily) — используется метод Open, который открывает канал дейтаграммы для одного адреса, в то время как параметризованный метод Open метод открытия канала для нескольких адресов, представленных в виде семейства протоколов.

read (ByteBuffer dst) — этот метод используется для чтения данных из данного буфера через канал дейтаграммы.

receive (ByteBuffer dst) — этот метод используется для получения дейтаграммы через этот канал.

send (ByteBuffer src, SocketAddress target) — этот метод используется для отправки дейтаграммы по этому каналу.

пример

В следующем примере показано, как отправить данные из Java NIO DataGramChannel.

Сервер: DatagramChannelServer.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

public class DatagramChannelServer {
   public static void main(String[] args) throws IOException {
      DatagramChannel server = DatagramChannel.open();
      InetSocketAddress iAdd = new InetSocketAddress("localhost", 8989);
      server.bind(iAdd);
      System.out.println("Server Started: " + iAdd);
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      //receive buffer from client.
      SocketAddress remoteAdd = server.receive(buffer);
      //change mode of buffer
      buffer.flip();
      int limits = buffer.limit();
      byte bytes[] = new byte[limits];
      buffer.get(bytes, 0, limits);
      String msg = new String(bytes);
      System.out.println("Client at " + remoteAdd + "  sent: " + msg);
      server.send(buffer,remoteAdd);
      server.close();
   }
}

Выход

Server Started: localhost/127.0.0.1:8989

Клиент: DatagramChannelClient.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

public class DatagramChannelClient {
   public static void main(String[] args) throws IOException {
      DatagramChannel client = null;
      client = DatagramChannel.open();

      client.bind(null);

      String msg = "Hello World!";
      ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
      InetSocketAddress serverAddress = new InetSocketAddress("localhost",
        8989);

      client.send(buffer, serverAddress);
      buffer.clear();
      client.receive(buffer);
      buffer.flip();
    
      client.close();
   }
}

Выход

Запущенный клиент распечатает следующий вывод на сервере.

Server Started: localhost/127.0.0.1:8989
Client at /127.0.0.1:64857  sent: Hello World!

Java NIO — Сокет Канал

Канал сокетов Java NIO — это канал выбираемого типа, который означает, что его можно мультиплексировать с помощью селектора, используемого для потоковых сокетов, соединяющих сокеты. Канал сокетов можно создать, вызвав его статический метод open () , при условии, что любой ранее существующий сокет еще не создан. present.Socket канал создается с помощью вызова метода open, но еще не подключен. Для подключения к сокету канал должен быть вызван метод connect (). Здесь следует упомянуть, что канал не подключен и выполняется попытка операции ввода-вывода. чтобы быть предпринятым, NotYetConnectedException генерируется этим каналом. Поэтому необходимо убедиться, что канал подключен до выполнения какой-либо операции ввода-вывода. Как только канал подключается, он остается подключенным, пока не будет закрыт. Состояние сокетного канала может быть определено путем вызова его метод isConnected .

Соединение канала сокета можно завершить, вызвав его метод finishConnect (). Можно ли определить, выполняется ли операция соединения или нет, путем вызова метода isConnectionPending. Канал сокета по умолчанию поддерживает неблокирующее соединение. Также поддерживается асинхронное отключение, которая похожа на асинхронную операцию закрытия, указанную в классе Channel.

Сокетные каналы безопасны для использования несколькими параллельными потоками. Они поддерживают одновременное чтение и запись, хотя не более одного потока может читать и не более одного потока может писать в любой момент времени. Методы connect и finishConnect взаимно синхронизируются друг с другом, и попытка инициировать операцию чтения или записи во время выполнения одного из этих методов будет блокироваться до тех пор, пока этот вызов не будет завершен.

Важные методы сокета канала

  • bind (SocketAddress local) — этот метод используется для привязки канала сокета к локальному адресу, который предоставляется в качестве параметра для этого метода.

  • connect (SocketAddress remote) — этот метод используется для подключения сокета к удаленному адресу.

  • finishConnect () — Этот метод используется для завершения процесса подключения канала сокета.

  • getRemoteAddress () — Этот метод возвращает адрес удаленного местоположения, к которому подключен сокет канала.

  • isConnected () — как уже упоминалось, этот метод возвращает статус подключения сокетного канала, т. е. подключен он или нет.

  • open () и open ((SocketAddress remote) — метод Open используется для открытия канала сокета без указанного адреса, в то время как параметризованный метод open открывает канал для указанного удаленного адреса и также подключается к нему. Этот удобный метод работает так, как если бы вызывал open ( ), вызывая метод connect для полученного канала сокета, передавая его удаленно, а затем возвращая этот канал.

  • read (ByteBuffer dst) — этот метод используется для чтения данных из данного буфера через канал сокета.

  • isConnectionPending () — Этот метод сообщает, выполняется или нет операция соединения на этом канале.

bind (SocketAddress local) — этот метод используется для привязки канала сокета к локальному адресу, который предоставляется в качестве параметра для этого метода.

connect (SocketAddress remote) — этот метод используется для подключения сокета к удаленному адресу.

finishConnect () — Этот метод используется для завершения процесса подключения канала сокета.

getRemoteAddress () — Этот метод возвращает адрес удаленного местоположения, к которому подключен сокет канала.

isConnected () — как уже упоминалось, этот метод возвращает статус подключения сокетного канала, т. е. подключен он или нет.

open () и open ((SocketAddress remote) — метод Open используется для открытия канала сокета без указанного адреса, в то время как параметризованный метод open открывает канал для указанного удаленного адреса и также подключается к нему. Этот удобный метод работает так, как если бы вызывал open ( ), вызывая метод connect для полученного канала сокета, передавая его удаленно, а затем возвращая этот канал.

read (ByteBuffer dst) — этот метод используется для чтения данных из данного буфера через канал сокета.

isConnectionPending () — Этот метод сообщает, выполняется или нет операция соединения на этом канале.

пример

В следующем примере показано, как отправить данные из Java NIO SocketChannel.

C: /Test/temp.txt

Hello World!

Клиент: SocketChannelClient.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;

public class SocketChannelClient {
   public static void main(String[] args) throws IOException {
      ServerSocketChannel serverSocket = null;
      SocketChannel client = null;
      serverSocket = ServerSocketChannel.open();
      serverSocket.socket().bind(new InetSocketAddress(9000));
      client = serverSocket.accept();
      System.out.println("Connection Set:  " + client.getRemoteAddress());
      Path path = Paths.get("C:/Test/temp1.txt");
      FileChannel fileChannel = FileChannel.open(path, 
         EnumSet.of(StandardOpenOption.CREATE, 
            StandardOpenOption.TRUNCATE_EXISTING,
            StandardOpenOption.WRITE)
         );      
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      while(client.read(buffer) > 0) {
         buffer.flip();
         fileChannel.write(buffer);
         buffer.clear();
      }
      fileChannel.close();
      System.out.println("File Received");
      client.close();
   }
}

Выход

Запущенный клиент ничего не напечатает, пока сервер не запустится.


Сервер: SocketChannelServer.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;

public class SocketChannelServer {
   public static void main(String[] args) throws IOException {
      SocketChannel server = SocketChannel.open();
      SocketAddress socketAddr = new InetSocketAddress("localhost", 9000);
      server.connect(socketAddr);

      Path path = Paths.get("C:/Test/temp.txt");
      FileChannel fileChannel = FileChannel.open(path);
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      while(fileChannel.read(buffer) > 0) {
         buffer.flip();
         server.write(buffer);
         buffer.clear();
      }
      fileChannel.close();
      System.out.println("File Sent");
      server.close();
   }
}

Выход

Запустив сервер напечатает следующее.

Connection Set:  /127.0.0.1:49558
File Received

Java NIO — ServerSocket Channel

Канал сокета сервера Java NIO снова является каналом выбираемого типа, используемым для потоковых сокетов, соединяющих сокеты. Канал сервера сокетов можно создать, вызвав его статический метод open () , при условии, что любой ранее существующий сокет еще не присутствует. Канал сервера сокетов создается путем вызова метода open, но еще не привязан. Для привязки сокета к каналу должен вызываться метод bind () .

Здесь необходимо упомянуть одну вещь: если канал не связан, и любая попытка ввода-вывода пытается быть предпринята, то NotYetBoundException выбрасывается этим каналом. Поэтому перед выполнением любой операции ввода-вывода необходимо убедиться, что канал ограничен.

Входящие соединения для канала сокета сервера прослушиваются путем вызова метода ServerSocketChannel.accept (). Когда метод accept () возвращается, он возвращает SocketChannel с входящим соединением. Таким образом, метод accept () блокируется до тех пор, пока не поступит входящее соединение. Если канал находится в неблокирующем режиме, метод accept немедленно вернет значение null, если нет ожидающих соединений. В противном случае он будет блокироваться на неопределенный срок, пока не будет доступно новое соединение или не возникнет ошибка ввода-вывода.

Сокет нового канала изначально не связан; он должен быть привязан к определенному адресу через один из методов привязки его сокета, прежде чем соединения могут быть приняты. Также новый канал создается путем вызова метода openServerSocketChannel общесистемного объекта SelectorProvider по умолчанию.

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

Точно так же данные могут быть записаны в канал сокета сервера с использованием метода write () с использованием буфера в качестве параметра. Обычно используется метод write в цикле while, так как необходимо повторять метод write () до тех пор, пока в буфере не останется доступных байтов для записи.

Важные методы сокета канала

  • bind (SocketAddress local) — этот метод используется для привязки канала сокета к локальному адресу, который предоставляется в качестве параметра для этого метода.

  • accept () — этот метод используется для принятия соединения с сокетом этого канала.

  • connect (SocketAddress remote) — этот метод используется для подключения сокета к удаленному адресу.

  • finishConnect () — Этот метод используется для завершения процесса подключения канала сокета.

  • getRemoteAddress () — Этот метод возвращает адрес удаленного местоположения, к которому подключен сокет канала.

  • isConnected () — как уже упоминалось, этот метод возвращает статус подключения сокетного канала, т. е. подключен он или нет.

  • open () — метод Open используется для открытия канала сокета без указанного адреса. Этот удобный метод работает так, как если бы он вызывал метод open (), вызывал метод connect для получающегося канала сокета сервера, передавал его удаленно, а затем возвращал канал.

  • read (ByteBuffer dst) — этот метод используется для чтения данных из данного буфера через канал сокета.

  • setOption (SocketOption <T> name, T value) — этот метод устанавливает значение параметра сокета.

  • socket () — этот метод извлекает сокет сервера, связанный с этим каналом.

  • validOps () — этот метод возвращает набор операций, идентифицирующий поддерживаемые операции этого канала. Каналы сервера сокетов поддерживают только принятие новых соединений, поэтому этот метод возвращает SelectionKey.OP_ACCEPT.

bind (SocketAddress local) — этот метод используется для привязки канала сокета к локальному адресу, который предоставляется в качестве параметра для этого метода.

accept () — этот метод используется для принятия соединения с сокетом этого канала.

connect (SocketAddress remote) — этот метод используется для подключения сокета к удаленному адресу.

finishConnect () — Этот метод используется для завершения процесса подключения канала сокета.

getRemoteAddress () — Этот метод возвращает адрес удаленного местоположения, к которому подключен сокет канала.

isConnected () — как уже упоминалось, этот метод возвращает статус подключения сокетного канала, т. е. подключен он или нет.

open () — метод Open используется для открытия канала сокета без указанного адреса. Этот удобный метод работает так, как если бы он вызывал метод open (), вызывал метод connect для получающегося канала сокета сервера, передавал его удаленно, а затем возвращал канал.

read (ByteBuffer dst) — этот метод используется для чтения данных из данного буфера через канал сокета.

setOption (SocketOption <T> name, T value) — этот метод устанавливает значение параметра сокета.

socket () — этот метод извлекает сокет сервера, связанный с этим каналом.

validOps () — этот метод возвращает набор операций, идентифицирующий поддерживаемые операции этого канала. Каналы сервера сокетов поддерживают только принятие новых соединений, поэтому этот метод возвращает SelectionKey.OP_ACCEPT.

пример

В следующем примере показано, как отправить данные из Java NIO ServerSocketChannel.

C: /Test/temp.txt

Hello World!

Клиент: SocketChannelClient.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;

public class SocketChannelClient {
   public static void main(String[] args) throws IOException {
      ServerSocketChannel serverSocket = null;
      SocketChannel client = null;
      serverSocket = ServerSocketChannel.open();
      serverSocket.socket().bind(new InetSocketAddress(9000));
      client = serverSocket.accept();
      System.out.println("Connection Set:  " + client.getRemoteAddress());
      Path path = Paths.get("C:/Test/temp1.txt");
      FileChannel fileChannel = FileChannel.open(path, 
         EnumSet.of(StandardOpenOption.CREATE, 
            StandardOpenOption.TRUNCATE_EXISTING,
            StandardOpenOption.WRITE)
         );      
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      while(client.read(buffer) > 0) {
         buffer.flip();
         fileChannel.write(buffer);
         buffer.clear();
      }
      fileChannel.close();
      System.out.println("File Received");
      client.close();
   }
}

Выход

Запущенный клиент ничего не напечатает, пока сервер не запустится.


Сервер: SocketChannelServer.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;

public class SocketChannelServer {
   public static void main(String[] args) throws IOException {
      SocketChannel server = SocketChannel.open();
      SocketAddress socketAddr = new InetSocketAddress("localhost", 9000);
      server.connect(socketAddr);
      Path path = Paths.get("C:/Test/temp.txt");
      FileChannel fileChannel = FileChannel.open(path);
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      while(fileChannel.read(buffer) > 0) {
         buffer.flip();
         server.write(buffer);
         buffer.clear();
      }
      fileChannel.close();
      System.out.println("File Sent");
      server.close();
   }
}

Выход

Запустив сервер напечатает следующее.

Connection Set:  /127.0.0.1:49558
File Received

Java NIO — Scatter

Как мы знаем, Java NIO является более оптимизированным API для операций ввода-вывода данных по сравнению с традиционным API ввода-вывода Java. Еще одна дополнительная поддержка, которую обеспечивает Java NIO, заключается в чтении / записи данных из / в несколько буферов в канал. Это многократное чтение и поддержка записи называется Scatter and Gather, в которой данные разбрасываются на несколько буферов из одного канала в случае чтения данных, в то время как данные собираются из нескольких буферов в один канал в случае записи данных.

Для достижения этого множественного чтения и записи из канала есть API ScatteringByteChannel и GatheringByteChannel, который Java NIO предоставляет для чтения и записи данных, как показано в примере ниже.

ScatteringByteChannel

Чтение из нескольких каналов — в этом мы сделали чтение данных из одного канала в несколько буферов. Для этого несколько буферов выделяются и добавляются в массив типа буфера. Затем этот массив передается в качестве параметра методу чтения () ScatteringByteChannel, который затем записывает данные из канала в той последовательности, в которой буферы находятся в массиве. Как только буфер заполнен, канал переходит к заполнению следующего буфера.

В следующем примере показано, как выполняется рассеяние данных в Java NIO.

C: /Test/temp.txt

Hello World!
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ScatteringByteChannel;

public class ScatterExample {	
   private static String FILENAME = "C:/Test/temp.txt";
   public static void main(String[] args) {
      ByteBuffer bLen1 = ByteBuffer.allocate(1024);
      ByteBuffer bLen2 = ByteBuffer.allocate(1024);
      FileInputStream in;
      try {
         in = new FileInputStream(FILENAME);
         ScatteringByteChannel scatter = in.getChannel();
         scatter.read(new ByteBuffer[] {bLen1, bLen2});
         bLen1.position(0);
         bLen2.position(0);
         int len1 = bLen1.asIntBuffer().get();
         int len2 = bLen2.asIntBuffer().get();
         System.out.println("Scattering : Len1 = " + len1);
         System.out.println("Scattering : Len2 = " + len2);
      } 
      catch (FileNotFoundException exObj) {
         exObj.printStackTrace();
      }
      catch (IOException ioObj) {
         ioObj.printStackTrace();
      }
   }
}

Выход

Scattering : Len1 = 1214606444
Scattering : Len2 = 0

В заключение можно сделать вывод, что подход «разброс / сбор» в Java NIO представлен как оптимизированный и многозадачный при правильном использовании. Он позволяет делегировать операционной системе тяжелую работу по разделению прочитанных данных на несколько сегментов или сборке. Несопоставимые фрагменты данных в целом. Несомненно, это экономит время и более эффективно использует операционную систему за счет исключения буферных копий и уменьшения объема кода, необходимого для записи и отладки.

Java NIO — собирать

Как мы знаем, Java NIO является более оптимизированным API для операций ввода-вывода данных по сравнению с традиционным API ввода-вывода Java. Еще одна дополнительная поддержка, которую обеспечивает Java NIO, заключается в чтении / записи данных из / в несколько буферов в канал. Это многократное чтение и поддержка записи называется Scatter and Gather, в которой данные разбрасываются на несколько буферов из одного канала в случае чтения данных, в то время как данные собираются из нескольких буферов в один канал в случае записи данных.

Для достижения этого множественного чтения и записи из канала есть API ScatteringByteChannel и GatheringByteChannel, который Java NIO предоставляет для чтения и записи данных, как показано в примере ниже.

GatheringByteChannel

запись в несколько каналов — в этом мы сделали запись данных из нескольких буферов в один канал. Для этого снова несколько буферов выделяются и добавляются в массив типа буфера. Затем этот массив передается в качестве параметра методу write () метода GatheringByteChannel который затем записывает данные из нескольких буферов в той последовательности, в которой эти буферы находятся в массиве. Следует помнить, что здесь записываются только данные между положением и пределом буферов.

В следующем примере показано, как осуществляется сбор данных в Java NIO.

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.GatheringByteChannel;

public class GatherExample {
   private static String FILENAME = "C:/Test/temp.txt";
   public static void main(String[] args) {
      String stream1 = "Gather data stream first";
      String stream2 = "Gather data stream second";
      ByteBuffer bLen1 = ByteBuffer.allocate(1024);
      ByteBuffer bLen2 = ByteBuffer.allocate(1024);
      // Next two buffer hold the data we want to write
      ByteBuffer bstream1 = ByteBuffer.wrap(stream1.getBytes());
      ByteBuffer bstream2 = ByteBuffer.wrap(stream2.getBytes());
      int len1 = stream1.length();
      int len2 = stream2.length();
      // Writing length(data) to the Buffer
      bLen1.asIntBuffer().put(len1);
      bLen2.asIntBuffer().put(len2);
      System.out.println("Gathering : Len1 = " + len1);
      System.out.println("Gathering : Len2 = " + len2);
      // Write data to the file
      try { 
         FileOutputStream out = new FileOutputStream(FILENAME);
         GatheringByteChannel gather = out.getChannel();						
         gather.write(new ByteBuffer[] {bLen1, bLen2, bstream1, bstream2});
         out.close();
         gather.close();
      }
      catch (FileNotFoundException exObj) {
         exObj.printStackTrace();
      }
      catch(IOException ioObj) {
         ioObj.printStackTrace();
      }
   }
}

Выход

Gathering : Len1 = 24
Gathering : Len2 = 25

В заключение можно сделать вывод, что подход «разброс / сбор» в Java NIO представлен как оптимизированный и многозадачный при правильном использовании. Он позволяет делегировать операционной системе тяжелую работу по разделению прочитанных данных на несколько сегментов или сборке. Несопоставимые фрагменты данных в целом. Несомненно, это экономит время и более эффективно использует операционную систему за счет исключения буферных копий и уменьшения объема кода, необходимого для записи и отладки.

Java NIO — буфер

Буферы в Java NIO можно рассматривать как простой объект, который действует как контейнер с фиксированным размером блоков данных, которые можно использовать для записи данных в канал или чтения данных из канала, чтобы буферы действовали как конечные точки для каналов.

Он предоставляет набор методов, которые делают более удобным обращение с блоком памяти для чтения и записи данных в и из каналов.

Буферы делают пакет NIO более эффективным и быстрым по сравнению с классическим вводом-выводом, поскольку в случае ввода-вывода данные обрабатываются в виде потоков, которые не поддерживают асинхронный и параллельный поток данных. Также ввод-вывод не позволяет выполнять данные в чанке или группе байтов. ,

Основные параметры, которые определяют буфер Java NIO, могут быть определены как —

  • Capacity — максимальный объем данных / байт, который может быть сохранен в Buffer. Емкость буфера не может быть изменена. Как только буфер заполнен, его следует очистить перед записью в него.

  • Лимит — Лимит имеет значение в соответствии с режимом Буфера, т.е. в режиме записи Буфера Лимит равен емкости, что означает, что максимальное количество данных, которые могут быть записаны в буфер. В то время как в режиме чтения буфера Лимит означает предел того, сколько данных может быть прочитанным из буфера.

  • Положение — указывает на текущее положение курсора в буфере. Первоначально устанавливается в 0 в момент создания буфера или, другими словами, это индекс следующего элемента, который должен быть прочитан или записан, который автоматически обновляется get () и помещается () методы.

  • Отметить — отметить закладку позиции в буфере. При вызове метода mark () записывается текущая позиция, а при вызове reset () отмеченная позиция восстанавливается.

Capacity — максимальный объем данных / байт, который может быть сохранен в Buffer. Емкость буфера не может быть изменена. Как только буфер заполнен, его следует очистить перед записью в него.

Лимит — Лимит имеет значение в соответствии с режимом Буфера, т.е. в режиме записи Буфера Лимит равен емкости, что означает, что максимальное количество данных, которые могут быть записаны в буфер. В то время как в режиме чтения буфера Лимит означает предел того, сколько данных может быть прочитанным из буфера.

Положение — указывает на текущее положение курсора в буфере. Первоначально устанавливается в 0 в момент создания буфера или, другими словами, это индекс следующего элемента, который должен быть прочитан или записан, который автоматически обновляется get () и помещается () методы.

Отметить — отметить закладку позиции в буфере. При вызове метода mark () записывается текущая позиция, а при вызове reset () отмеченная позиция восстанавливается.

Тип буфера

Буферы Java NIO могут быть классифицированы в следующих вариантах на основе типов данных, с которыми имеет дело буфер —

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

Важные методы буфера

Как уже упоминалось, что Buffer действует как объект памяти, который предоставляет набор методов, которые делают более удобным работу с блоком памяти. Ниже приведены важные методы Buffer —

  • allocate (intacity) — Этот метод используется для выделения нового буфера с емкостью в качестве параметра. Метод Allocate выдает исключение IllegalArgumentException в случае, если переданная емкость является отрицательным целым числом.

  • read () и put () — метод чтения канала используется для записи данных из канала в буфер, а put — метод буфера, который используется для записи данных в буфер.

  • flip () — Метод flip переключает режим буфера с режима записи на режим чтения. Он также устанавливает позицию обратно в 0 и устанавливает предел, в котором позиция была во время записи.

  • write () и get () — метод записи канала используется для записи данных из буфера в канал, в то время как get является методом буфера, который используется для чтения данных из буфера.

  • rewind () — метод перемотки используется, когда требуется перечитывание, так как он устанавливает позицию в ноль и не изменяет значение лимита.

  • clear () и compact () — clear и compact оба метода используются для перехода из режима чтения в режим записи. Метод clear () устанавливает позицию в ноль и ограничивает ее до емкости, в этом методе данные в буфере не очищаются, только маркеры инициализируются повторно.

    С другой стороны, метод compact () используется, когда осталось несколько непрочитанных данных, и все же мы используем режим записи буфера, в этом случае компактный метод копирует все непрочитанные данные в начало буфера и устанавливает положение сразу после последнего непрочитанного элемента. Свойство limit все еще установлено в емкость.

  • mark () и reset () — Как следует из названия, метод mark используется для пометки какой-либо конкретной позиции в буфере, в то время как сброс делает положение обратно в отмеченную позицию.

allocate (intacity) — Этот метод используется для выделения нового буфера с емкостью в качестве параметра. Метод Allocate выдает исключение IllegalArgumentException в случае, если переданная емкость является отрицательным целым числом.

read () и put () — метод чтения канала используется для записи данных из канала в буфер, а put — метод буфера, который используется для записи данных в буфер.

flip () — Метод flip переключает режим буфера с режима записи на режим чтения. Он также устанавливает позицию обратно в 0 и устанавливает предел, в котором позиция была во время записи.

write () и get () — метод записи канала используется для записи данных из буфера в канал, в то время как get является методом буфера, который используется для чтения данных из буфера.

rewind () — метод перемотки используется, когда требуется перечитывание, так как он устанавливает позицию в ноль и не изменяет значение лимита.

clear () и compact () — clear и compact оба метода используются для перехода из режима чтения в режим записи. Метод clear () устанавливает позицию в ноль и ограничивает ее до емкости, в этом методе данные в буфере не очищаются, только маркеры инициализируются повторно.

С другой стороны, метод compact () используется, когда осталось несколько непрочитанных данных, и все же мы используем режим записи буфера, в этом случае компактный метод копирует все непрочитанные данные в начало буфера и устанавливает положение сразу после последнего непрочитанного элемента. Свойство limit все еще установлено в емкость.

mark () и reset () — Как следует из названия, метод mark используется для пометки какой-либо конкретной позиции в буфере, в то время как сброс делает положение обратно в отмеченную позицию.

пример

В следующем примере показана реализация определенных выше методов.

import java.nio.ByteBuffer;
import java.nio.CharBuffer;

public class BufferDemo {
   public static void main (String [] args) {
      //allocate a character type buffer.
      CharBuffer buffer = CharBuffer.allocate(10);
      String text = "bufferDemo";
      System.out.println("Input text: " + text);
      for (int i = 0; i < text.length(); i++) {
         char c = text.charAt(i);
         //put character in buffer.
		 buffer.put(c);
      }
      int buffPos = buffer.position();
      System.out.println("Position after data is written into buffer: " + buffPos);
      buffer.flip();
      System.out.println("Reading buffer contents:");
      while (buffer.hasRemaining()) {
         System.out.println(buffer.get());                   
      }
      //set the position of buffer to 5.
      buffer.position(5);
      //sets this buffer's mark at its position
      buffer.mark();
      //try to change the position
      buffer.position(6);
      //calling reset method to restore to the position we marked.
      //reset() raise InvalidMarkException if either the new position is less
      //than the position marked or merk has not been setted.
      buffer.reset();
      System.out.println("Restored buffer position : " + buffer.position());
   }
}

Выход

Input text: bufferDemo
Position after data is written into buffer: 10
Reading buffer contents:
b
u
f
f
e
r
D
e
m
o
Restored buffer position : 5

Java NIO — Селектор

Как мы знаем, Java NIO поддерживает множественные транзакции от и до каналов и буферов. Таким образом, чтобы изучить один или несколько каналов NIO и определить, какие каналы готовы к транзакции данных, т. Е. Чтение или запись, Java NIO обеспечивает Selector.

С помощью Selector мы можем создать поток, который будет знать, какой канал готов для записи и чтения данных и может обрабатывать этот конкретный канал.

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

SelectionKey — это набор операций, которые можно выполнить с каналом, или мы можем сказать, что мы можем узнать состояние канала с помощью клавиши выбора.

Основные операции или состояние канала, представленные клавишей выбора:

  • SelectionKey.OP_CONNECT — канал, который готов к подключению к серверу.

  • SelectionKey.OP_ACCEPT — канал, который готов принимать входящие соединения.

  • SelectionKey.OP_READ — канал, который готов к чтению данных.

  • SelectionKey.OP_WRITE — канал, который готов к записи данных.

SelectionKey.OP_CONNECT — канал, который готов к подключению к серверу.

SelectionKey.OP_ACCEPT — канал, который готов принимать входящие соединения.

SelectionKey.OP_READ — канал, который готов к чтению данных.

SelectionKey.OP_WRITE — канал, который готов к записи данных.

Ключ выбора, полученный после регистрации, имеет несколько важных методов, как указано ниже —

  • attach () — этот метод используется для прикрепления объекта с помощью ключа. Основная цель присоединения объекта к каналу — это распознавание того же канала.

  • attachment () — этот метод используется для сохранения прикрепленного объекта из канала.

  • channel () — Этот метод используется для получения канала, для которого создается конкретный ключ.

  • selector () — этот метод используется для получения селектора, для которого создан определенный ключ.

  • isValid () — Этот метод возвращает погоду, ключ действителен или нет.

  • isReadable () — Этот метод заявляет, что канал ключа погоды готов для чтения или нет.

  • isWritable () — этот метод утверждает, что канал ключа погоды готов к записи или нет.

  • isAcceptable () — Этот метод сообщает, что канал ключа погоды готов к приему входящего соединения или нет.

  • isConnectable () — Этот метод проверяет, завершил ли канал этого ключа свою операцию соединения через сокет.

  • isAcceptable () — Этот метод проверяет, готов ли канал этого ключа принять новое соединение с сокетом.

  • InterestOps () — Этот метод получает набор интересов этого ключа.

  • readyOps () — этот метод извлекает готовый набор, представляющий собой набор операций, для которых канал готов.

attach () — этот метод используется для прикрепления объекта с помощью ключа. Основная цель присоединения объекта к каналу — это распознавание того же канала.

attachment () — этот метод используется для сохранения прикрепленного объекта из канала.

channel () — Этот метод используется для получения канала, для которого создается конкретный ключ.

selector () — этот метод используется для получения селектора, для которого создан определенный ключ.

isValid () — Этот метод возвращает погоду, ключ действителен или нет.

isReadable () — Этот метод заявляет, что канал ключа погоды готов для чтения или нет.

isWritable () — этот метод утверждает, что канал ключа погоды готов к записи или нет.

isAcceptable () — Этот метод сообщает, что канал ключа погоды готов к приему входящего соединения или нет.

isConnectable () — Этот метод проверяет, завершил ли канал этого ключа свою операцию соединения через сокет.

isAcceptable () — Этот метод проверяет, готов ли канал этого ключа принять новое соединение с сокетом.

InterestOps () — Этот метод получает набор интересов этого ключа.

readyOps () — этот метод извлекает готовый набор, представляющий собой набор операций, для которых канал готов.

Мы можем выбрать канал из селектора, вызвав его статический метод select (). Метод выбора селектора перегружен как —

  • select () — этот метод блокирует текущий поток, пока хотя бы один канал не будет готов к событиям, для которых он зарегистрирован.

  • select (long timeout) — Этот метод делает то же самое, что и select (), за исключением того, что он блокирует поток на максимальное время ожидания в миллисекундах (параметр).

  • selectNow () — этот метод вообще не блокируется. Он сразу же возвращается, когда каналы готовы.

select () — этот метод блокирует текущий поток, пока хотя бы один канал не будет готов к событиям, для которых он зарегистрирован.

select (long timeout) — Этот метод делает то же самое, что и select (), за исключением того, что он блокирует поток на максимальное время ожидания в миллисекундах (параметр).

selectNow () — этот метод вообще не блокируется. Он сразу же возвращается, когда каналы готовы.

Также для того, чтобы оставить заблокированный поток, который вызывает метод select, из экземпляра селектора можно вызвать метод wakeup (), после чего поток, ожидающий внутри select (), немедленно вернется.

Наконец, мы можем закрыть селектор, вызвав метод close (), который также делает недействительными все экземпляры SelectionKey, зарегистрированные в этом селекторе, вместе с закрытием селектора.

пример

import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class SelectorDemo {
   public static void main(String[] args) throws IOException {
      String demo_text = "This is a demo String";	
      Selector selector = Selector.open();
      ServerSocketChannel serverSocket = ServerSocketChannel.open();
      serverSocket.bind(new InetSocketAddress("localhost", 5454));
      serverSocket.configureBlocking(false);
      serverSocket.register(selector, SelectionKey.OP_ACCEPT);
      ByteBuffer buffer = ByteBuffer.allocate(256);
      while (true) {
         selector.select();
         Set<SelectionKey> selectedKeys = selector.selectedKeys();
         Iterator<SelectionKey> iter = selectedKeys.iterator();
         while (iter.hasNext()) {
            SelectionKey key = iter.next();
            int interestOps = key.interestOps();
            System.out.println(interestOps);
            if (key.isAcceptable()) {
               SocketChannel client = serverSocket.accept();
               client.configureBlocking(false);
               client.register(selector, SelectionKey.OP_READ);
            }
            if (key.isReadable()) {
               SocketChannel client = (SocketChannel) key.channel();
               client.read(buffer);
               if (new String(buffer.array()).trim().equals(demo_text)) {
                  client.close();
                  System.out.println("Not accepting client messages anymore");
               }
               buffer.flip();
               client.write(buffer);
               buffer.clear();
            }
            iter.remove();
         }
      }
   }
}

Java NIO — Труба

В Java канал NIO — это компонент, который используется для записи и чтения данных между двумя потоками. Труба в основном состоит из двух каналов, которые отвечают за распространение данных.

Среди двух составляющих каналов один называется каналом Sink, который в основном предназначен для записи данных, а другой — каналом Source, основная цель которого — считывать данные из канала Sink.

Синхронизация данных сохраняется в порядке во время записи и чтения данных, поскольку необходимо обеспечить, чтобы данные были прочитаны в том же порядке, в котором они записаны в канал.

Следует помнить, что это однонаправленный поток данных в канале, т.е. данные записываются только в канале приемника и могут быть прочитаны только из канала источника.

В Java канал NIO определяется как абстрактный класс, состоящий в основном из трех методов, из которых два являются абстрактными.

Методы класса Труба

  • open () — этот метод используется для получения экземпляра Pipe, или мы можем сказать, что pipe создан путем вызова этого метода.

  • sink () — Этот метод возвращает канал приемника канала, который используется для записи данных, вызывая его метод записи.

  • source () — Этот метод возвращает исходный канал канала, который используется для чтения данных, вызывая его метод чтения.

open () — этот метод используется для получения экземпляра Pipe, или мы можем сказать, что pipe создан путем вызова этого метода.

sink () — Этот метод возвращает канал приемника канала, который используется для записи данных, вызывая его метод записи.

source () — Этот метод возвращает исходный канал канала, который используется для чтения данных, вызывая его метод чтения.

пример

В следующем примере показана реализация Java NIO pipe.

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;

public class PipeDemo {
   public static void main(String[] args) throws IOException {
      //An instance of Pipe is created
      Pipe pipe = Pipe.open();
      // gets the pipe's sink channel
      Pipe.SinkChannel skChannel = pipe.sink();
      String testData = "Test Data to Check java NIO Channels Pipe.";
      ByteBuffer buffer = ByteBuffer.allocate(512);
      buffer.clear();
      buffer.put(testData.getBytes());
      buffer.flip();
      //write data into sink channel.
      while(buffer.hasRemaining()) {
         skChannel.write(buffer);
      }
      //gets  pipe's source channel
      Pipe.SourceChannel sourceChannel = pipe.source();
      buffer = ByteBuffer.allocate(512);
      //write data into console     
      while(sourceChannel.read(buffer) > 0){
         //limit is set to current position and position is set to zero
         buffer.flip();
         while(buffer.hasRemaining()){
            char ch = (char) buffer.get();
            System.out.print(ch);
         }
         //position is set to zero and limit is set to capacity to clear the buffer.
         buffer.clear();
      }
   }
}

Выход

Test Data to Check java NIO Channels Pipe.

Предположим, у нас есть текстовый файл c: /test.txt , который имеет следующее содержимое. Этот файл будет использоваться в качестве входных данных для нашего примера программы.

Java NIO — путь

Как следует из названия, Path — это конкретное местоположение объекта, такого как файл или каталог в файловой системе, чтобы можно было искать и получать к нему доступ в этом конкретном месте.

С технической точки зрения Java, Path — это интерфейс, который был представлен в файловом пакете Java NIO во время Java версии 7, и представляет собой представление местоположения в конкретной файловой системе. Поскольку интерфейс пути находится в пакете Java NIO, он получает свое квалифицированное имя как java. .nio.file.Path.

В общем случае путь объекта может быть двух типов: один — абсолютный путь, а другой — относительный путь. Поскольку имя обоих путей предполагает, что абсолютный путь — это адрес местоположения от корня до объекта, в котором он находится, а относительный путь — это адрес местоположения. который относится к какому-либо другому пути. В своем определении Path использует разделители как «\» для Windows и «/» для операционных систем Unix.

Чтобы получить экземпляр Path, мы можем использовать статический метод класса java.nio.file.Paths get (). Этот метод преобразует строку пути или последовательность строк, которые при соединении образуют строку пути, в экземпляр Path Этот метод также генерирует InvalidPathException во время выполнения, если переданные аргументы содержат недопустимые символы.

Как упомянуто выше, абсолютный путь извлекается путем передачи корневого элемента и полного списка каталогов, необходимого для нахождения файла. При этом относительный путь может быть получен путем объединения базового пути с относительным путем. Извлечение обоих путей будет проиллюстрировано в следующем примере.

пример

package com.java.nio;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.file.FileSystem;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
   public static void main(String[] args) throws IOException {
      Path relative = Paths.get("file2.txt");
      System.out.println("Relative path: " + relative);
      Path absolute = relative.toAbsolutePath();
      System.out.println("Absolute path: " + absolute);
   }
}

Пока мы знаем, что такое интерфейс пути, зачем он нам нужен и как мы можем получить к нему доступ. Теперь мы знаем, какие важные методы нам предоставляет интерфейс пути.

Важные методы Path Interface

  • getFileName () — возвращает файловую систему, которая создала этот объект.

  • getName () — возвращает элемент имени этого пути в виде объекта Path.

  • getNameCount () — возвращает количество элементов имени в пути.

  • subpath () — возвращает относительный путь, который является подпоследовательностью элементов имени этого пути.

  • getParent () — Возвращает родительский путь, или нуль, если у этого пути нет родителя.

  • getRoot () — возвращает корневой компонент этого пути в виде объекта Path или значение NULL, если этот путь не имеет корневого компонента.

  • toAbsolutePath () — Возвращает объект Path, представляющий абсолютный путь этого пути.

  • toRealPath () — возвращает реальный путь к существующему файлу.

  • toFile () — возвращает объект File, представляющий этот путь.

  • normalize () — Возвращает путь, который является этим путем с исключенными избыточными элементами имени.

  • compareTo (Path other) — сравнивает два абстрактных пути лексикографически. Этот метод возвращает ноль, если аргумент равен этому пути, значение меньше нуля, если этот путь лексикографически меньше аргумента, или значение больше нуля, если этот путь лексикографически больше, чем аргумент.

  • endWith (Path other) — Проверяет, заканчивается ли этот путь заданным путем. Если в указанном пути есть N элементов, и нет корневого компонента, и этот путь имеет N или более элементов, то этот путь заканчивается указанным путем, если последний N элементы каждого пути, начиная с самого дальнего от корня элемента, равны.

  • endWith (String other) — Проверяет, заканчивается ли этот путь путем Path, созданным путем преобразования заданной строки пути, точно так, как указано методом endWith (Path).

getFileName () — возвращает файловую систему, которая создала этот объект.

getName () — возвращает элемент имени этого пути в виде объекта Path.

getNameCount () — возвращает количество элементов имени в пути.

subpath () — возвращает относительный путь, который является подпоследовательностью элементов имени этого пути.

getParent () — Возвращает родительский путь, или нуль, если у этого пути нет родителя.

getRoot () — возвращает корневой компонент этого пути в виде объекта Path или значение NULL, если этот путь не имеет корневого компонента.

toAbsolutePath () — Возвращает объект Path, представляющий абсолютный путь этого пути.

toRealPath () — возвращает реальный путь к существующему файлу.

toFile () — возвращает объект File, представляющий этот путь.

normalize () — Возвращает путь, который является этим путем с исключенными избыточными элементами имени.

compareTo (Path other) — сравнивает два абстрактных пути лексикографически. Этот метод возвращает ноль, если аргумент равен этому пути, значение меньше нуля, если этот путь лексикографически меньше аргумента, или значение больше нуля, если этот путь лексикографически больше, чем аргумент.

endWith (Path other) — Проверяет, заканчивается ли этот путь заданным путем. Если в указанном пути есть N элементов, и нет корневого компонента, и этот путь имеет N или более элементов, то этот путь заканчивается указанным путем, если последний N элементы каждого пути, начиная с самого дальнего от корня элемента, равны.

endWith (String other) — Проверяет, заканчивается ли этот путь путем Path, созданным путем преобразования заданной строки пути, точно так, как указано методом endWith (Path).

пример

Следующий пример иллюстрирует различные методы интерфейса Path, которые упомянуты выше —

package com.java.nio;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.file.FileSystem;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
   public static void main(String[] args) throws IOException {
      Path path = Paths.get("D:/workspace/ContentW/Saurav_CV.docx");
      FileSystem fs =  path.getFileSystem();
      System.out.println(fs.toString());
      System.out.println(path.isAbsolute());
      System.out.println(path.getFileName());
      System.out.println(path.toAbsolutePath().toString());
      System.out.println(path.getRoot());
      System.out.println(path.getParent());
      System.out.println(path.getNameCount());
      System.out.println(path.getName(0));
      System.out.println(path.subpath(0, 2));
      System.out.println(path.toString());
      System.out.println(path.getNameCount());
      Path realPath = path.toRealPath(LinkOption.NOFOLLOW_LINKS);
      System.out.println(realPath.toString());
      String originalPath = "d:\\data\\projects\\a-project\\..\\another-project";
      Path path1 = Paths.get(originalPath);
      Path path2 = path1.normalize();
      System.out.println("path2 = " + path2);
   }
}

Java NIO — Файл

Пакет Java NIO предоставляет еще один служебный API с именем Files, который в основном используется для манипулирования файлами и каталогами с использованием его статических методов, который в основном работает с объектом Path.

Как упомянуто в руководстве по Path, этот интерфейс Path представлен в пакете Java NIO во время версии Java 7 в пакете файла. Так что это руководство предназначено для того же пакета File.

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

Есть много методов, определенных в классе Files, которые также могут быть прочитаны из документации Java. В этом руководстве мы попытались охватить некоторые важные методы среди всех методов класса Java NIO Files.

Важные методы класса Files.

Ниже приведены важные методы, определенные в классе Java NIO Files.

  • createFile (Path filePath, FileAttribute attrs) — класс Files предоставляет этот метод для создания файла с использованием указанного пути.

createFile (Path filePath, FileAttribute attrs) — класс Files предоставляет этот метод для создания файла с использованием указанного пути.

пример

package com.java.nio;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class CreateFile {
   public static void main(String[] args) {
      //initialize Path object
      Path path = Paths.get("D:file.txt");
      //create file
      try {
         Path createdFilePath = Files.createFile(path);
         System.out.println("Created a file at : "+createdFilePath);
      } 
      catch (IOException e) {
         e.printStackTrace();
      }
   }
}

Выход

Created a file at : D:\data\file.txt
  • copy (InputStream in, Path target, CopyOption… options) — Этот метод используется для копирования всех байтов из указанного входного потока в указанный целевой файл и возвращает число байтов, прочитанных или записанных как длинное значение. LinkOption для этого параметра со следующими значениями —

    • COPY_ATTRIBUTES — скопировать атрибуты в новый файл, например, атрибут последнего изменения.

    • REPLACE_EXISTING — заменить существующий файл, если он существует.

    • NOFOLLOW_LINKS — если файл является символической ссылкой, то копируется сама ссылка, а не цель ссылки.

copy (InputStream in, Path target, CopyOption… options) — Этот метод используется для копирования всех байтов из указанного входного потока в указанный целевой файл и возвращает число байтов, прочитанных или записанных как длинное значение. LinkOption для этого параметра со следующими значениями —

COPY_ATTRIBUTES — скопировать атрибуты в новый файл, например, атрибут последнего изменения.

REPLACE_EXISTING — заменить существующий файл, если он существует.

NOFOLLOW_LINKS — если файл является символической ссылкой, то копируется сама ссылка, а не цель ссылки.

пример

package com.java.nio;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
public class WriteFile {
   public static void main(String[] args) {
      Path sourceFile = Paths.get("D:file.txt");
      Path targetFile = Paths.get("D:fileCopy.txt");
      try {
         Files.copy(sourceFile, targetFile,
         StandardCopyOption.REPLACE_EXISTING);
      }
      catch (IOException ex) {
         System.err.format("I/O Error when copying file");
      }
      Path wiki_path = Paths.get("D:fileCopy.txt");
      Charset charset = Charset.forName("ISO-8859-1");
      try {
         List<String> lines = Files.readAllLines(wiki_path, charset);
         for (String line : lines) {
            System.out.println(line);
         }
      } 
      catch (IOException e) {
         System.out.println(e);
      }
   }	
}

Выход

To be or not to be?
  • createDirectories (Path dir, FileAttribute <?> … attrs) — этот метод используется для создания каталогов с использованием заданного пути путем создания всех несуществующих родительских каталогов.

  • delete (путь к файлу) — этот метод используется для удаления файла с указанного пути. Он генерирует исключение NoSuchFileException, если файл не существует по указанному пути или файл является каталогом, и он может быть не пустым и не может быть удален.

  • exist (Path path) — этот метод используется, чтобы проверить, существует ли файл по указанному пути, и если файл существует, он вернет true или же он вернет false.

  • readAllBytes (Path path) — этот метод используется для чтения всех байтов из файла по заданному пути и возвращает байтовый массив, содержащий байты, прочитанные из файла.

createDirectories (Path dir, FileAttribute <?> … attrs) — этот метод используется для создания каталогов с использованием заданного пути путем создания всех несуществующих родительских каталогов.

delete (путь к файлу) — этот метод используется для удаления файла с указанного пути. Он генерирует исключение NoSuchFileException, если файл не существует по указанному пути или файл является каталогом, и он может быть не пустым и не может быть удален.

exist (Path path) — этот метод используется, чтобы проверить, существует ли файл по указанному пути, и если файл существует, он вернет true или же он вернет false.

readAllBytes (Path path) — этот метод используется для чтения всех байтов из файла по заданному пути и возвращает байтовый массив, содержащий байты, прочитанные из файла.

пример

package com.java.nio;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class ReadFile {
   public static void main(String[] args) {
      Path wiki_path = Paths.get("D:file.txt");
      Charset charset = Charset.forName("ISO-8859-1");
      try {
         List<String> lines = Files.readAllLines(wiki_path, charset);
         for (String line : lines) {
            System.out.println(line);
         }
      } 
      catch (IOException e) {
         System.out.println(e);
      }
   }	
}

Выход

Welcome to file.
  • size (Path path) — этот метод используется для получения размера файла по указанному пути в байтах.

  • write (Path path, byte [] bytes, OpenOption… options) — Этот метод используется для записи байтов в файл по указанному пути.

size (Path path) — этот метод используется для получения размера файла по указанному пути в байтах.

write (Path path, byte [] bytes, OpenOption… options) — Этот метод используется для записи байтов в файл по указанному пути.

пример

package com.java.nio;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class WriteFile {
   public static void main(String[] args) {
      Path path = Paths.get("D:file.txt");
      String question = "To be or not to be?";
      Charset charset = Charset.forName("ISO-8859-1");
      try {
         Files.write(path, question.getBytes());
         List<String> lines = Files.readAllLines(path, charset);
         for (String line : lines) {
            System.out.println(line);
         }
      } 
      catch (IOException e) {
         System.out.println(e);
      }
   }
}

Выход

To be or not to be?

Java NIO — AsynchronousFileChannel

Поскольку мы знаем, что Java NIO поддерживает параллелизм и многопоточность, что позволяет нам одновременно работать с разными каналами. Таким образом, API, ответственный за это в пакете Java NIO, — это AsynchronousFileChannel, который определен в пакете каналов NIO. для AsynchronousFileChannel — это java.nio.channels.AsynchronousFileChannel .

AsynchronousFileChannel аналогичен FileChannel NIO, за исключением того, что этот канал позволяет файловым операциям выполняться асинхронно, в отличие от операции синхронного ввода-вывода, в которой поток входит в действие и ожидает завершения запроса. Таким образом, асинхронные каналы безопасны для использования. несколькими параллельными потоками.

В асинхронном запросе поток передается ядру операционной системы, чтобы выполнить его, в то время как поток продолжает обрабатывать другое задание. Как только задание ядра выполнено, он сигнализирует потоку, затем поток подтверждает сигнал и прерывает текущее задание и обрабатывает Работа ввода / вывода по мере необходимости.

Для достижения параллелизма этот канал предоставляет два подхода, один из которых заключается в возврате объекта java.util.concurrent.Future, а другой — в передачу операции типа java.nio.channels.CompletionHandler .

Мы разберем оба подхода с помощью примеров один за другим.

  • Future Object — в этом случае экземпляр Future Interface возвращается из канала. В Future interface есть метод get (), который возвращает состояние операции, которая обрабатывается асинхронно, на основе которой может быть принято решение о дальнейшем выполнении другой задачи. Мы можем также проверьте, выполнена ли задача или нет, вызвав ее метод isDone .

Future Object — в этом случае экземпляр Future Interface возвращается из канала. В Future interface есть метод get (), который возвращает состояние операции, которая обрабатывается асинхронно, на основе которой может быть принято решение о дальнейшем выполнении другой задачи. Мы можем также проверьте, выполнена ли задача или нет, вызвав ее метод isDone .

пример

В следующем примере показано, как использовать объект Future и выполнять асинхронные задачи.

package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class FutureObject {
   public static void main(String[] args) throws Exception {
      readFile();
   }
   private static void readFile() throws IOException, InterruptedException, ExecutionException {
      String filePath = "D:fileCopy.txt";
      printFileContents(filePath);
      Path path = Paths.get(filePath);		
      AsynchronousFileChannel channel =AsynchronousFileChannel.open(path, StandardOpenOption.READ);
      ByteBuffer buffer = ByteBuffer.allocate(400);
      Future<Integer> result = channel.read(buffer, 0); // position = 0
      while (! result.isDone()) {
         System.out.println("Task of reading file is in progress asynchronously.");
      }
      System.out.println("Reading done: " + result.isDone());
      System.out.println("Bytes read from file: " + result.get()); 
      buffer.flip();
      System.out.print("Buffer contents: ");
      while (buffer.hasRemaining()) {
         System.out.print((char) buffer.get());                
      }
      System.out.println(" ");
      buffer.clear();
      channel.close();
   }
   private static void printFileContents(String path) throws IOException {
      FileReader fr = new FileReader(path);
      BufferedReader br = new BufferedReader(fr);
      String textRead = br.readLine();
      System.out.println("File contents: ");
      while (textRead != null) {
         System.out.println("     " + textRead);
         textRead = br.readLine();
      }
   fr.close();
   br.close();
   }
}

Выход

File contents: 
   To be or not to be?
   Task of reading file is in progress asynchronously.
   Task of reading file is in progress asynchronously.
   Reading done: true
   Bytes read from file: 19
   Buffer contents: To be or not to be? 
  • Обработчик завершения

    Этот подход довольно прост, поскольку в этом мы используем интерфейс CompletionHandler и переопределяем два его метода: один метод complete (), который вызывается при успешном завершении операции ввода-вывода, а другой — метод fail (), который вызывается, если операции ввода-вывода fails.In при этом создается обработчик для использования результата асинхронной операции ввода-вывода, поскольку после завершения задачи только обработчик имеет функции, которые выполняются.

Обработчик завершения

Этот подход довольно прост, поскольку в этом мы используем интерфейс CompletionHandler и переопределяем два его метода: один метод complete (), который вызывается при успешном завершении операции ввода-вывода, а другой — метод fail (), который вызывается, если операции ввода-вывода fails.In при этом создается обработчик для использования результата асинхронной операции ввода-вывода, поскольку после завершения задачи только обработчик имеет функции, которые выполняются.

пример

В следующем примере показано, как использовать CompletionHandler для асинхронной задачи.

package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class CompletionHandlerDemo {
   public static void main (String [] args) throws Exception {
      writeFile();
   }
   private static void writeFile() throws IOException {
      String input = "Content to be written to the file.";
      System.out.println("Input string: " + input);
      byte [] byteArray = input.getBytes();
      ByteBuffer buffer = ByteBuffer.wrap(byteArray);
      Path path = Paths.get("D:fileCopy.txt");
      AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
      CompletionHandler handler = new CompletionHandler() {
         @Override
         public void completed(Object result, Object attachment) {
            System.out.println(attachment + " completed and " + result + " bytes are written.");
         }
         @Override
         public void failed(Throwable exc, Object attachment) {
            System.out.println(attachment + " failed with exception:");
            exc.printStackTrace();
         }
      };
      channel.write(buffer, 0, "Async Task", handler);
      channel.close();
      printFileContents(path.toString());
   }
   private static void printFileContents(String path) throws IOException {
      FileReader fr = new FileReader(path);
      BufferedReader br = new BufferedReader(fr);
      String textRead = br.readLine();
      System.out.println("File contents: ");
      while (textRead != null) {
         System.out.println("     " + textRead);
         textRead = br.readLine();
      }
      fr.close();
      br.close();
   }
}

Выход

Input string: Content to be written to the file.
Async Task completed and 34 bytes are written.
File contents: 
Content to be written to the file.

Java NIO — CharSet

В Java для каждого символа есть четко определенные единицы кода Unicode, которые внутренне обрабатываются JVM. Поэтому пакет Java NIO определяет абстрактный класс с именем Charset, который в основном используется для кодирования и декодирования charset и UNICODE.

Стандартные кодировки

Поддерживаемые Charset в Java приведены ниже.

  • US-ASCII — Семиразрядные символы ASCII.

  • ISO-8859-1 — ISO Латинский алфавит.

  • UTF-8 — это 8-битный формат преобразования UCS.

  • UTF-16BE — это 16-битный формат преобразования UCS с порядком байтов с прямым порядком байтов.

  • UTF-16LE — это 16-битное преобразование UCS с байтовым порядком байтов.

  • UTF-16 — 16-битный формат преобразования UCS.

US-ASCII — Семиразрядные символы ASCII.

ISO-8859-1 — ISO Латинский алфавит.

UTF-8 — это 8-битный формат преобразования UCS.

UTF-16BE — это 16-битный формат преобразования UCS с порядком байтов с прямым порядком байтов.

UTF-16LE — это 16-битное преобразование UCS с байтовым порядком байтов.

UTF-16 — 16-битный формат преобразования UCS.

Важные методы класса Charset

  • forName () — Этот метод создает объект charset для данного имени charset. Имя может быть каноническим или псевдонимом.

  • displayName () — Этот метод возвращает каноническое имя данной кодировки.

  • canEncode () — Этот метод проверяет, поддерживает ли данный набор символов кодировку или нет.

  • decode () — этот метод декодирует строку заданного набора символов в буферный код набора символов Unicode.

  • encode () — Этот метод кодирует charbuffer кодировки unicode в буфер байтов данной кодировки.

forName () — Этот метод создает объект charset для данного имени charset. Имя может быть каноническим или псевдонимом.

displayName () — Этот метод возвращает каноническое имя данной кодировки.

canEncode () — Этот метод проверяет, поддерживает ли данный набор символов кодировку или нет.

decode () — этот метод декодирует строку заданного набора символов в буферный код набора символов Unicode.

encode () — Этот метод кодирует charbuffer кодировки unicode в буфер байтов данной кодировки.

пример

Следующий пример иллюстрирует важные методы класса Charset.

package com.java.nio;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
public class CharsetExample {
   public static void main(String[] args) {
      Charset charset = Charset.forName("US-ASCII");
      System.out.println(charset.displayName());
      System.out.println(charset.canEncode());
      String str = "Demo text for conversion.";
      //convert byte buffer in given charset to char buffer in unicode
      ByteBuffer byteBuffer = ByteBuffer.wrap(str.getBytes());
      CharBuffer charBuffer = charset.decode(byteBuffer);
      //convert char buffer in unicode to byte buffer in given charset
      ByteBuffer newByteBuffer = charset.encode(charBuffer);
      while(newbb.hasRemaining()){
         char ch = (char) newByteBuffer.get();
         System.out.print(ch);
      }
      newByteBuffer.clear();
   }
}

Выход

US-ASCII
Demo text for conversion.

Java NIO — FileLock

Как мы знаем, Java NIO поддерживает параллелизм и многопоточность, что позволяет ему работать с несколькими потоками, работающими с несколькими файлами одновременно. Но в некоторых случаях нам требуется, чтобы наш файл не получал общий доступ ни от одного потока и не был доступен.

Для такого требования NIO снова предоставляет API, известный как FileLock, который используется для обеспечения блокировки всего файла или его части, чтобы файл или его часть не были доступны для общего доступа.

чтобы обеспечить или применить такую ​​блокировку, мы должны использовать FileChannel или AsynchronousFileChannel, который предоставляет для этой цели два метода lock () и tryLock (). Предоставляемая блокировка может быть двух типов:

  • Эксклюзивная блокировка — эксклюзивная блокировка не позволяет другим программам получать перекрывающуюся блокировку любого типа.

  • Общая блокировка . Общая блокировка не позволяет другим одновременно работающим программам получать перекрывающуюся эксклюзивную блокировку, но позволяет им получать перекрывающиеся общие блокировки.

Эксклюзивная блокировка — эксклюзивная блокировка не позволяет другим программам получать перекрывающуюся блокировку любого типа.

Общая блокировка . Общая блокировка не позволяет другим одновременно работающим программам получать перекрывающуюся эксклюзивную блокировку, но позволяет им получать перекрывающиеся общие блокировки.

Методы, используемые для получения блокировки над файлом —

  • lock () — этот метод FileChannel или AsynchronousFileChannel получает эксклюзивную блокировку для файла, связанного с данным каналом. Типом возврата этого метода является FileLock, который далее используется для мониторинга полученной блокировки.

  • lock (long position, long size, boolean shared) — этот метод снова является перегруженным методом блокировки и используется для блокировки определенной части файла.

  • tryLock () — этот метод возвращает FileLock или null, если блокировка не может быть получена, и он пытается получить явно исключительную блокировку для файла этого канала.

  • tryLock (long position, long size, boolean shared) — этот метод пытается получить блокировку в заданной области файла этого канала, которая может быть эксклюзивной или общего типа.

lock () — этот метод FileChannel или AsynchronousFileChannel получает эксклюзивную блокировку для файла, связанного с данным каналом. Типом возврата этого метода является FileLock, который далее используется для мониторинга полученной блокировки.

lock (long position, long size, boolean shared) — этот метод снова является перегруженным методом блокировки и используется для блокировки определенной части файла.

tryLock () — этот метод возвращает FileLock или null, если блокировка не может быть получена, и он пытается получить явно исключительную блокировку для файла этого канала.

tryLock (long position, long size, boolean shared) — этот метод пытается получить блокировку в заданной области файла этого канала, которая может быть эксклюзивной или общего типа.

Методы класса FileLock

  • acquBy () — этот метод возвращает канал, для которого была получена блокировка файла.

  • position () — этот метод возвращает позицию в файле первого байта заблокированной области. Блокированная область не должна содержаться внутри или даже перекрывать фактический базовый файл, поэтому значение, возвращаемое этим методом, может превышать текущий размер.

  • size () — этот метод возвращает размер заблокированной области в байтах. Блокированная область не должна содержаться внутри или даже перекрывать фактический базовый файл, поэтому значение, возвращаемое этим методом, может превышать текущий размер файла.

  • isShared () — Этот метод используется для определения того, является ли блокировка общей или нет.

  • overlaps (длинная позиция, длинный размер) — этот метод сообщает, перекрывает ли эта блокировка заданный диапазон блокировки.

  • isValid () — этот метод сообщает, действительна ли полученная блокировка. Объект блокировки остается действительным до тех пор, пока он не будет освобожден или соответствующий канал файла не будет закрыт, в зависимости от того, что произойдет раньше.

  • release () — Освобождает полученную блокировку. Если объект блокировки действителен, то вызов этого метода освобождает блокировку и делает объект недействительным. Если этот объект блокировки недействителен, то вызов этого метода не имеет никакого эффекта.

  • close () — этот метод вызывает метод release (). Он был добавлен в класс, чтобы его можно было использовать вместе с блочной конструкцией автоматического управления ресурсами.

acquBy () — этот метод возвращает канал, для которого была получена блокировка файла.

position () — этот метод возвращает позицию в файле первого байта заблокированной области. Блокированная область не должна содержаться внутри или даже перекрывать фактический базовый файл, поэтому значение, возвращаемое этим методом, может превышать текущий размер.

size () — этот метод возвращает размер заблокированной области в байтах. Блокированная область не должна содержаться внутри или даже перекрывать фактический базовый файл, поэтому значение, возвращаемое этим методом, может превышать текущий размер файла.

isShared () — Этот метод используется для определения того, является ли блокировка общей или нет.

overlaps (длинная позиция, длинный размер) — этот метод сообщает, перекрывает ли эта блокировка заданный диапазон блокировки.

isValid () — этот метод сообщает, действительна ли полученная блокировка. Объект блокировки остается действительным до тех пор, пока он не будет освобожден или соответствующий канал файла не будет закрыт, в зависимости от того, что произойдет раньше.

release () — Освобождает полученную блокировку. Если объект блокировки действителен, то вызов этого метода освобождает блокировку и делает объект недействительным. Если этот объект блокировки недействителен, то вызов этого метода не имеет никакого эффекта.

close () — этот метод вызывает метод release (). Он был добавлен в класс, чтобы его можно было использовать вместе с блочной конструкцией автоматического управления ресурсами.

Пример для демонстрации блокировки файла.

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

package com.java.nio;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FileLockExample {
   public static void main(String[] args) throws IOException {
      String input = "Demo text to be written in locked mode.";  
      System.out.println("Input string to the test file is: " + input);  
      ByteBuffer buf = ByteBuffer.wrap(input.getBytes());  
      String fp = "D:file.txt";  
      Path pt = Paths.get(fp);  
      FileChannel channel = FileChannel.open(pt, StandardOpenOption.WRITE,StandardOpenOption.APPEND);  
      channel.position(channel.size() - 1); // position of a cursor at the end of file       
      FileLock lock = channel.lock();   
      System.out.println("The Lock is shared: " + lock.isShared());  
      channel.write(buf);  
      channel.close(); // Releases the Lock  
      System.out.println("Content Writing is complete. Therefore close the channel and release the lock.");  
      PrintFileCreated.print(fp);  
   }  
}