Введение

Java. nio (NIO расшифровывается как New Input/Output) — это набор API языка программирования Java, предоставляющих возможности для выполнения интенсивных операций ввода-вывода. Он был представлен в составе Java J2SE 1.4 компанией Sun Microsystems в дополнение к существующей стандартной системе ввода-вывода. NIO был разработан в рамках Java Community Process как JSR 51. Расширение NIO, предлагающее новый API файловой системы под названием NIO.2, было выпущено вместе с Java SE 7 ("Dolphin").

Буферы NIO

Передача данных в NIO основана на буферах (и связанных классах). Эти классы представляют собой непрерывный блок памяти вместе с небольшим набором операций передачи данных. Хотя теоретически это структуры данных общего назначения, реализация может выбирать память с учетом требований к выравниванию или организации постраничной памяти, которые недоступны иным способом в Java. Как правило, это позволяет содержимому буфера занимать ту же физическую память, что и основная операционная система для своих собственных операций ввода-вывода, обеспечивая тем самым наиболее прямой механизм передачи и устраняя необходимость в дополнительном копировании. В большинстве операционных систем, при условии, что конкретный участок памяти обладает необходимыми свойствами, передача может осуществляться без участия процессора. Буферы NIO намеренно имеют ограниченный набор функций для достижения этих целей. Существуют классы буферов для всех примитивных типов Java, кроме boolean, которые могут совместно использовать память с байтовыми буферами и обеспечивать произвольную интерпретацию базовых байтов.

Использование

Буферы NIO поддерживают несколько указателей, которые определяют работу их методов доступа. Реализация буфера NIO содержит богатый набор методов для изменения этих указателей: метод `flip` не выполняет "переворот" или подкачку в каноническом смысле, а перемещает указатель позиции к началу базового массива (если он есть) и указатель предела – в прежнюю позицию указателя позиции. Предоставлены три метода `get` для извлечения данных из буфера NIO. Реализация для работы с блоками данных, вместо выполнения операции "получения" в традиционном смысле, "записывает" данные в указанный массив. Аргумент "смещение", передаваемый этому методу, относится не к смещению внутри буфера, из которого выполняется чтение, и не к смещению от указателя позиции, а к смещению от 0 в пределах целевого массива. Если не используются абсолютные методы `get` и `put`, любая операция `get` или `put` выполняется от указателя позиции. Если необходимо читать из другой позиции в базовом массиве, не изменяя позицию записи, предусмотрены методы `mark` и `reset`. Метод `mark` эффективно сохраняет позицию указателя позиции, устанавливая указатель отметки в текущую позицию указателя позиции. Метод `reset` перемещает указатель позиции в позицию указателя отметки. При вызове метода `clear` или `flip` указатель отметки отбрасывается. Метод `clear` не гарантирует обнуление буфера, но возвращает указатель предела к верхней границе базового массива, а указатель позиции – к нулю. Операции `put` и `get` для буферов NIO не являются потокобезопасными. Можно отобразить область памяти размером от 0 до `Integer.MAX_VALUE` (2 ГБ); области, превышающие этот предел, можно получить доступ, используя смещение больше нуля.

Селекторы

Селектор (и подклассы) предоставляет механизм ожидания событий на каналах и определения момента, когда один или несколько каналов готовы к передаче данных. При регистрации нескольких каналов в селекторе, он позволяет блокировать выполнение программы до тех пор, пока хотя бы один канал не станет доступным, или пока не произойдет событие прерывания. Хотя подобное мультиплексирование можно реализовать с помощью потоков, селектор может обеспечить значительно более эффективную реализацию, используя низкоуровневые механизмы операционной системы. Например, в POSIX-совместимых операционных системах существуют прямые аналоги этих концепций, такие как `select`. Важным применением данной конструкции является распространенный подход в серверном программном обеспечении, заключающийся в одновременном ожидании ответов по множеству соединений.

Набор символов

В Java, кодировка символов — это соответствие между символами Unicode (или их подмножеством) и байтами. Пакет NIO предоставляет средства для определения кодировок символов и обеспечения алгоритмами кодирования и декодирования для новых соответствий.

Прием

Неожиданно, что канал, связанный с файлом Java IO RandomAccess, закрывает файловый дескриптор при возникновении прерывания, в то время как собственный метод `read` класса `RandomAccessFile` этого не делает.

JDK 7 и NIO.2

JDK 7 включает в себя пакет, который, вместе с классом (также новым в JDK 7), среди прочих функций, предоставляет расширенные возможности для задач файловой системы, например, позволяет работать с символическими и жесткими ссылками, а также быстрее, чем старый класс File, выгружать большие списки содержимого каталогов в буферы. Пакет и связанный с ним пакет обеспечивают всестороннюю поддержку операций ввода-вывода с файлами и доступа к файловой системе. В JDK 7 также доступен провайдер файловой системы zip. `java.nio.file.LinkOption` является примером эмуляции расширяемых перечислений с помощью интерфейсов. В Java невозможно, чтобы одно перечисление наследовалось от другого. Однако можно эмулировать расширяемый тип перечисления, заставляя перечисление реализовывать один или несколько интерфейсов. `LinkOption` – это тип перечисления, который реализует интерфейсы `OpenOption` и `CopyOption`, что эмулирует поведение расширяемого перечисления. Недостатком этого подхода является то, что реализации нельзя наследовать между различными типами перечислений.