Основы, связанные с NIO 1

Java задняя часть Операционная система API
Основы, связанные с NIO 1

Пожалуйста, указывайте первоисточник при перепечатке, спасибо!

скажи это прямо

Знания, связанные с 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].


Личный публичный аккаунт, добро пожаловать, чтобы обратить внимание и проверить более замечательную историю! ! !

匠心零度公众号