categories: Java
—-

NIO解释

NIO是一种IO模型,相对于经典IO,是非阻塞的。

NIO模型

image.png
相比经典io基于流的传输,NIO采用的是缓冲区的方式,基于块的传输

Channel分类

  • FileChannel
    • FileChannnel允许你向文件里读写内容
  • DatagramChannel
    • DatagramChannel允许你通过UDP协议读写网络上的内容
  • SocketChannel
    • SocketChannel允许你通过TCP协议读写网络上的内容
  • ServerSocketChannel

    • allows you to listen for incoming TCP connections, like a web server does. For each incoming connection a SocketChannel is created.

      NIO读写文件Demo

      1. public static void main(String[] args) throws IOException {
      2. RandomAccessFile afile=new RandomAccessFile("E:\\Nio.txt","rw");//使用RandomAccessFile创建文件对象
      3. FileChannel fileChannel=afile.getChannel();//获取channel
      4. ByteBuffer byteBuffer=ByteBuffer.allocate(1024);//创建buffer
      5. String mess="fighting for beatiful girl";
      6. int j=fileChannel.read(byteBuffer);//这个j代表了一次读出来的字符个数
      7. while (j!=-1){
      8. System.out.println("reads: "+j);
      9. // byteBuffer.flip();//这个flip很重要,修改buffer的模式,由写模式转换为读模式
      10. // while (byteBuffer.hasRemaining()){//把字符读完
      11. // System.out.print((char)byteBuffer.get());
      12. // }
      13. // byteBuffer.clear();//本次独处的字符输出完了,清空bytebuffer。
      14. j=fileChannel.read(byteBuffer);//buffer此时又是写模式
      15. }
      16. byte[] we=mess.getBytes(StandardCharsets.UTF_8);
      17. byteBuffer.put(we);
      18. byteBuffer.flip();//将buffer切换为读模式
      19. fileChannel.write(byteBuffer);//将buffer里的东西写入文件
      20. afile.close();//关闭文件资源
      21. }

      Buffer

      buffer的使用步骤

      Using a Buffer to read and write data typically follows this little 4-step process:

  1. Write data into the Buffer
  2. Call buffer.flip()
  3. Read data out of the Buffer
  4. Call buffer.clear() or buffer.compact()

    buffer的三个参数

  • capacity
  • position
  • limit

image.png

Capacity

Being a memory block, a Buffer has a certain fixed size, also called its “capacity”. You can only write capacity bytes, longs, chars etc. into the Buffer. Once the Buffer is full, you need to empty it (read the data, or clear it) before you can write more data into it.

Position

  • When you write data into the Buffer, you do so at a certain position. Initially the position is 0. When a byte, long etc. has been written into the Buffer the position is advanced to point to the next cell in the buffer to insert data into. Position can maximally become capacity - 1.

  • When you read data from a Buffer you also do so from a given position. When you flip a Buffer from writing mode to reading mode, the position is reset back to 0. As you read data from the Buffer you do so from position, and position is advanced to next position to read.

    Limit

    In write mode the limit of a Buffer is the limit of how much data you can write into the buffer. In write mode the limit is equal to the capacity of the Buffer.

When flipping the Buffer into read mode, limit means the limit of how much data you can read from the data. Therefore, when flipping a Buffer into read mode, limit is set to write position of the write mode. In other words, you can read as many bytes as were written (limit is set to the number of bytes written, which is marked by position).

buffer的类别

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

每个基本类型,都有相应的Buffer

初始化buffer

  1. ByteBuffer buf = ByteBuffer.allocate(48);//用的最多的Buffer
  2. CharBuffer buf = CharBuffer.allocate(1024);

向buffer中写入数据

  1. int bytesRead = inChannel.read(buf); //read into buffer.从channel中读取数据,写入到buffer
  2. buf.put(127); //直接往buffer里put数据

flip()

The flip() method switches a Buffer from writing mode to reading mode. Calling flip() sets the position back to 0, and sets the limit to where position just was.
In other words, position now marks the reading position, and limit marks how many bytes, chars etc. were written into the buffer - the limit of how many bytes, chars etc. that can be read.

将buffer从写模式切换到读模式。limit为buffer中有多少数据,position切换为0;

从buffer中读取数据

There are two ways you can read data from a Buffer.

  1. Read data from the buffer into a channel.
  2. Read data from the buffer yourself, using one of the get() methods. ```java

int bytesWritten = inChannel.write(buf);//从buffer中读取数据,并写入channel,返回一个int,代表写入了多少数据 byte aByte = buf.get();//获取一个字符

  1. There are many other versions of the `get()` method, allowing you to read data from the `Buffer` in many different ways. For instance, reading at specific positions, or reading an array of bytes from the buffer. See the JavaDoc for the concrete buffer implementation for more details.
  2. <a name="W6OgH"></a>
  3. ## rewind()
  4. The `Buffer.rewind()` sets the `position` back to 0, so you can reread all the data in the buffer. The `limit` remains untouched, thus still marking how many elements (bytes, chars etc.) that can be read from the `Buffer`.
  5. > bufferposition设置为0;这样就可以从0开始读取数据。limit不改变
  6. <a name="ZgPEo"></a>
  7. ## clear() and compact()
  8. Once you are done reading data out of the `Buffer` you have to make the `Buffer` ready for writing again. You can do so either by calling `clear()` or by calling `compact()`.<br />If you call `clear()` the `position` is set back to 0 and the `limit` to `capacity`. In other words, the `Buffer` is cleared. The data in the `Buffer` is not cleared. Only the markers telling where you can write data into the `Buffer` are.<br />If there is any unread data in the `Buffer` when you call `clear()` that data will be "forgotten", meaning you no longer have any markers telling what data has been read, and what has not been read.<br />If there is still unread data in the `Buffer`, and you want to read it later, but you need to do some writing first, call `compact()` instead of `clear()`.<br />`compact()` copies all unread data to the beginning of the `Buffer`. Then it sets `position` to right after the last unread element. The `limit` property is still set to `capacity`, just like `clear()` does. Now the `Buffer` is ready for writing, but you will not overwrite the unread data.
  9. > 当你读了数据之后,应该调用clear方法或者compact方法来使buffer重新可读。
  10. > 1. clear方法会将position设置为0limit设置为capacity大小。但是数据并不会清空。同时你也不会知道是否还有数据没有读,有未读的数据你也读不出来。
  11. > 1. compact方法,会将未读的数据移到buffer的开头,并将position置为未读的数据的最后一位,limit依然设置为capacity,但是你不会覆写未读的数据。
  12. <a name="x9zil"></a>
  13. ## mark() and reset()
  14. You can mark a given position in a `Buffer` by calling the `Buffer.mark()` method. You can then later reset the position back to the marked position by calling the `Buffer.reset()` method. Here is an example:
  15. ```java
  16. buffer.mark();
  17. //call buffer.get() a couple of times, e.g. during parsing.
  18. buffer.reset(); //set position back to mark.

你可以调用 mark方法。将buffer此时的position标记起来。并可通过reset方法,恢复到标记的位点