Пожалуйста, указывайте первоисточник при перепечатке, спасибо!
скажи это прямо
Знания, связанные с NIO, — это много дополнительных базовых знаний, поэтому сегодняшняя статья — это просто краткое введение, и в продолжении будет один или два связанных с NIO контента.
Что такое НИО
Java NIO (New IO) — это новый API ввода-вывода, появившийся после Java 1.4, который может заменить стандартный API ввода-вывода Java. NIO имеет ту же функцию и назначение, что и исходный IO, но используется совершенно по-другому.NIO поддерживает операции ввода-вывода, ориентированные на буфер, на основе каналов. NIO будет читать и записывать файлы более эффективно.
Основное отличие NIO от обычного IO
IO | NIO |
---|---|
Потоковая ориентация | Буферно-ориентированный |
Блокирующий ввод-вывод (блокирующий ввод-вывод) | Неблокирующий ввод-вывод (неблокирующий ввод-вывод) |
(без) | Селекторы |
- Каналы и буферы: стандартный ввод-вывод работает с потоками байтов и символьными потоками, в то время как NIO работает с каналами и буферами, и данные всегда считываются из каналов в область буферов или записываются из буфера в канал.
- Асинхронный ввод-вывод (Asynchronous IO): Java NIO позволяет использовать ввод-вывод асинхронно, например: когда поток считывает данные из канала в буфер, поток все еще может делать другие вещи. Пока данные записываются в буфер, поток может продолжать их обработку. Запись в канал из буфера аналогична.
- Селекторы: Java NIO представляет концепцию селекторов, которые используются для прослушивания событий по нескольким каналам (например, открытие соединения, поступление данных). Поэтому один поток может прослушивать несколько каналов данных.
**Примечание: **Асинхронный ввод-вывод (асинхронный ввод-вывод), селекторы (селекторы) и другие последующие статьи будут продолжаться.
Буфер
Из основного различия между NIO и обычным вводом-выводом, приведенным выше, мы также можем видеть, что в основных операциях ввода-вывода все операции основаны на потоках, тогда как в NIO все операции основаны на буферах и продолжают работать.Все операции выполняются через область буфера Буфер представляет собой линейный и упорядоченный набор данных, который может вместить только данные определенного типа (в основном, буфер или начальный класс, соответствующий базовому типу данных).
Буферные классы для каждого типа данных
Класс кеша | Связанное описание |
---|---|
ByteBuffer | Буфер для хранения байтов |
CharBuffer | Буфер для хранения символов |
ShortBuffer | Буфер, в котором хранятся короткие целые числа |
IntBuffer | Буфер, в котором хранятся целые числа |
LongBuffer | Буфер, в котором хранятся длинные целые числа |
FloatBuffer | Сохраняет буфер одинарной точности с плавающей запятой |
DoubleBuffer | Хранить буфер двойной точности с плавающей запятой |
**Примечания:** Думаете ли вы о 8 основных типах данных JAVA, когда видите вышеперечисленные категории?Единственное, чего не хватает, это логическое значениеДля типа.
Первый вопрос: почему логическое значение не нужно кэшировать?Вы можете прочитать то, что было написано ранее:Java, связанный с двоичным кодом, который описывает внутреннее представление и хранение чисел в спецификации.Булево значение занимает 1 бит (значение только истинное или ложное).Поскольку байт является основным типом данных, используемым операционной системой и всеми устройствами ввода-вывода, поэтому в основном, он представлен байтами или непрерывным сегментом байтов, поэтому логическое значение отсутствует, и нет необходимости в операциях кэширования логического типа (например, исходный код RocketMQ может использовать бит в Int для представления логического значения, а другие биты продолжают хранить данные,Добро пожаловать в мой публичный аккаунт [изобретательность ноль], как использовать вышеуказанные техники в последующем анализе исходного кода RocketMQ и т. д. На самом деле, несколько статей, которые я написал выше, были подготовлены для последующего анализа исходного кода RocketMQ).
Использование буфера
Чтение данных:
- метод флип()
- Переключить буфер из режима записи в режим чтения
- Вызов метода flip() установит позицию обратно на 0 и установит ограничение на предыдущее значение позиции.
- buf.flip();
- buf.get()
- читать данные
- Buffer.rewind()
- Установите позицию обратно на 0, чтобы вы могли перечитать все данные в буфере
- Ограничение остается прежним, по-прежнему указывает, сколько элементов (byte, char и т. д.) можно прочитать из буфера.
- Метод Buffer.mark() может отметить определенную позицию в буфере. можно будет позвонить позже.
- Метод Buffer.reset() восстанавливает позицию, когда она была отмечена Buffer.mark().
- Метод clear() будет:
- Очистить весь буфер.
- position будет установлено обратно на 0, а предел будет установлен на значение емкости
- компактный() метод:
- Очищаются только данные, которые уже были прочитаны; любые непрочитанные данные перемещаются в начало буфера, а вновь записанные данные помещаются после непрочитанных данных буфера.
- Позиция устанавливается сразу после последнего непрочитанного элемента, а ограничение устанавливается на значение емкости.
Записать данные: buf.put(127);
Основные свойства буфера
- емкость: указывает максимальную емкость данных буфера, емкость буфера не может быть отрицательной и не может быть изменена после создания.
- ограничение: индекс первых данных, которые нельзя читать или записывать, т. е. данные после лимита недоступны для чтения или записи. Предел буфера не может быть отрицательным и не может превышать его емкость.
- позиция: Индекс следующих данных для чтения или записи. Позиция буфера не может быть отрицательной и не может превышать его предел.
**Примечание: **Марка, позиция, предел, вместимость подчиняются следующему инварианту: 0
Чтобы объяснить важные атрибуты выше, легко понять, чтобы подготовить простой код и карту.
//第一步,获取IntBuffer,通过IntBuffer.allocate操作
IntBuffer buf = IntBuffer.allocate(10) ; // 准备出10个大小的缓冲区
//第二步未操作前输出属性值
System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ;
//第三步进行设置数据
buf.put(6) ; // 设置一个数据
buf.put(16) ; // 设置二个数据
//第四步操作后输出属性值
System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ;
//第五步将Buffer从写模式切换到读模式 postion = 0 ,limit = 原本position
buf.flip() ;
//第六步操作后输出属性值
System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ;
Вывод программы:
position = 0,limit = 10,capacty = 10
position = 2,limit = 10,capacty = 10
position = 0,limit = 2,capacty = 10
Для иллюстрации см. диаграмму ниже:
Канал
Каналы представляют собой открытые соединения с устройствами ввода-вывода (например, файлы, сокеты). Если вам нужно использовать систему NIO, вам нужно получить канал для подключения устройства ввода-вывода и буфер для хранения данных. Затем манипулируйте буфером для обработки данных. Канал отвечает за передачу, Буфер отвечает за хранение. Каналы определяются пакетом java.nio.channels. Канал представляет собой открытое соединение между источником ввода-вывода и пунктом назначения. Каналы похожи на традиционные «потоки». Просто сам Канал не может напрямую обращаться к данным, а Канал может взаимодействовать только с Буфером.
Каналы — это все буферы операций для выполнения всех функций.
Все известные классы реализации канала в Java:
- AbstractInterruptibleChannel
- AbstractSelectableChannel
- DatagramChannel
- FileChannel
- Pipe.SinkChannel
- Pipe.SourceChannel
- SelectableChannel
- ServerSocketChannel
- SocketChannel
Обычно используются следующие:
- FileChannel: канал для чтения, записи, отображения и управления файлами.
- DatagramChannel: Чтение и запись каналов данных в сети через UDP.
- SocketChannel: Чтение и запись данных в сети через TCP.
- ServerSocketChannel: он может отслеживать новые входящие TCP-соединения и создавать SocketChannel для каждого нового входящего соединения.
получить канал
Один из способов получить канал — вызвать метод getChannel() для объекта, поддерживающего канал. Классы, поддерживающие каналы, следующие:
- FileInputStream
- FileOutputStream
- RandomAccessFile
- DatagramSocket
- Socket
- ServerSocket
Другой способ получить канал — использовать статический метод newByteChannel() класса Files для получения байтового канала. Или откройте и верните указанный канал через статический метод канала open() .
FileChannel
- Чтобы более наглядно объяснить Канал, его легко понять с помощью некоторых простых кодов FileChannel.
- Подготовка основана на классе FileOutputStream, оба из которых поддерживают операции с каналами.
String info[] = {"欢迎","关注","匠心零度","的","公众号","谢谢!!"} ;
File file = new File("d:" + File.separator + "testfilechannel.txt") ;
FileOutputStream output = null ;
FileChannel fout = null;
try {
output = new FileOutputStream(file) ;
fout = null;
fout = output.getChannel() ; // 得到输出的通道
ByteBuffer buf = ByteBuffer.allocate(1024) ;
for(int i=0;i<info.length;i++){
buf.put(info[i].getBytes()) ; // 字符串变为字节数组放进缓冲区之中
}
buf.flip() ;
fout.write(buf) ; // 输出缓冲区的内容
} catch (Exception e) {
e.printStackTrace();
}finally{
if(fout!=null){
try {
fout.close() ;
} catch (IOException e) {
e.printStackTrace();
}
}
if(output!=null){
try {
output.close() ;
} catch (IOException e) {
e.printStackTrace();
}
}
}
Эффект запуска программы:
**Примечание:**Сегодня только первая глава основ, связанных с NIO, поэтому многие из них не были рассмотрены. Я надеюсь, что то, что я сказал выше, даст вам новое понимание, продолжение следует...
Если вы чувствуете себя вознагражденным после прочтения, пожалуйста, поставьте лайк, подпишитесь и добавьте общедоступную учетную запись [Ingenuity Zero].
Личный публичный аккаунт, добро пожаловать, чтобы обратить внимание и проверить более замечательную историю! ! !