Abstract: NIO stands for New IO, and this library was introduced in JDK1.4. NIO and IO have the same function and purpose, but the implementation method is different. NIO mainly uses blocks, so NIO is much more efficient than IO.

What is the difference between NIO and IO in Java?

NIO stands for New IO, and this library was introduced in JDK1.4. NIO and IO have the same function and purpose, but the implementation method is different. NIO mainly uses blocks, so NIO is much more efficient than IO.

Q: What is the difference between NIO and standard IO?

A:

  • Standard IO, which operates based on byte streams and character streams, blocking IO.
  • NIO operates based on channels and buffers, supports non-blocking IO, and provides selectors

JavaNIO Core 3 Components:

Channels Channels

Q: Can a Channel object read and write at the same time? Or do you need to create both input and output objects to read and write, as standard IO does?

A: A Channel is bidirectional. You can read or write data from A Channel. As you can see, you can call both read and write, depending on the buffer.

FileChannel fileChannel = FileChannel.open(new File("a.txt").toPath());
    ByteBuffer buf = ByteBuffer.allocate(1024);
     fileChannel.read(buf);
     fileChannel.write(buf);
Copy the code
  • Note that filechannel.read (buf) reads data from a.txt to BUf, a.txt->buf
  • Filechannel. write(buf) writes data from buF to a.txt (buf ->a.txt).
  • Channel and buffer relationship

Q: Does the channel support asynchronous reads and writes

A: support.

Q: Do channel reads and writes depend on the buffer?

A: It’s usually buffer dependent. However, transmission between two pipes is also supported, that is, direct reads and writes between pipes.

String[] arr=new String[]{"a.txt","b.txt"}; FileChannel in=new FileInputStream(arr[0]).getChannel(); FileChannel out =new FileOutputStream(arr[1]).getChannel(); In. TransferTo (0, in.size(), out);Copy the code

Common channels

  • FileChannel

A FileChannel in Java NIO is a channel to connect to a file. You can read and write files through file channels. FileChannel cannot be set to non-blocking mode; it always runs in blocking mode

Create a way

RandomAccessFile    file = new RandomAccessFile("D:/aa.txt");
FileChannel    fileChannel = file.getChannel();
Copy the code
  • SocketChannel

A SocketChannel in Java NIO is a channel that connects to a TCP network socket.

Supports non-blocking mode socketChannel. ConfigureBlocking (false).

You can create a SocketChannel in either of the following ways:

Open a SocketChannel and connect to a server on the Internet.

When a new connection reaches ServerSocketChannel, a SocketChannel is created

Create a way

SocketChannel socketChannel = SocketChannel.open(); SocketChannel. Connect (new InetSocketAddress (80) "192.168.1.100,");Copy the code
  • ServerSocketChannel

The ServerSocketChannel in Java NIO is a channel that listens for incoming TCP connections, just like the ServerSocket in standard IO.

The ServerSocketChannel class is in the java.nio.Channels package.

The difference between SocketChannel and ServerSocketChannel is that the former is used by the client and the latter is used by the server

Creation method:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket.bind(new InetSocketAddress(80)); serverSocketChannel.configureBlocking(false); while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); if(socketChannle ! = null) doSomething... }Copy the code

Buffer the Buffer

  • Buffer is where we actually get or write data.
  • File <-> buffer<-> data
  • A buffer is a buffer that can be read or written. It has two modes: read and write.
  • The capacity attribute of the buffer defines the maximum capacity of each buffer. The following 1024 is capacity.

ByteBuffer buf = ByteBuffer.allocate(1024);

  • The buffer has a position property that represents the current read/write position.
  • Position increases when data is written to buffer.
  • Position The maximum value is capacity-1
  • Writing data from a fileChannel file to a buffer is called write mode
  • After writing, flip is called and the postion of buffer is set to 0. At this point, it is ready to read the data in buffer (buffer.get()).

(Flip went from write mode to read mode!)

Q: What does position change to when buffer calls flip() to switch from write mode to read mode?

A: It becomes 0.

ByteBuffer buf = ByteBuffer.allocate(1024); Int byteRead = filechannel.read (buf); System.out.println("position=" + buf.position()+", byteRead=" + byteRead); buf.flip(); 0 system.out. println("position=" + buf.position());Copy the code
  • Buffer has 1 limit attribute.
  • In write mode, the buffer limit is the capacity of the buffer.

Q: What is the limit of buffer when it switches from write to read mode?

A: Flip () is called before each switch, after which limit is position in write mode.

int byteRead = fileChannel.read(buf); Println ("limit=" + buf.limit() + ",postion=" + buf.position()); system.out.println ("limit=" + buf.limit() + ",postion=" + buf.position()); System.out.println(" switch to read mode "); buf.flip(); System.out.println("limit=" + buf.limit());Copy the code

The results are as follows

Q: What are the ways to write data to the BUF buffer?

A:

  • int byteRead = fileChannel.read(buf);

Reading data from the channel to the BUF is equivalent to writing data to the BUF buffer.

  • Buf. PutChar (‘ a ‘);

Manually write character A to buf, postion plus 1.

Q: What are the ways to read data from the BUF buffer?

  • int bytesWrite = fileChannel.write(buf)

Data from the BUF is written to the pipe, which is equivalent to a fileChannel reading data from the BUF.

  • byte getByte = buf.get()

Manually read 1 character in BUF, postion plus 1.

Q: What are the methods of manually modifying the postion of the current buffer?

A:

  • Rewind () sets postion to 0
  • Mark () can mark a specific position, which is equivalent to marking. After a session, you can reset() to the previous mark() position (just like you need mark for these blog posts!).

Q: Does a channel channel support multiple buffers?

A: Yes. The write and read methods of the channel both support passing in an array of buffers, which are read and written sequentially.

Types of buffers:

Three other methods of Buffer:

  • warp:

When generating a fixed ByteBuffer from a byte[], using bytebuffer.wrap () is illegal. It generates a new buffer directly from the byte[] array with the same values.

  • Slice:

I get the sliced array.

  • Duplicate:

The duplicate method returns a duplicate of the original Buffer, including position, limit, and Capacity

  • Attention!

Warp \slice\duplicte’s get and put buffers operate on the same array as the original buffers

So making changes to the copied buffer also changes the original buffer and vice versa

Duplicte and slice are used to manipulate poistion\limit, but do not alter the original content, which would cause the original buffer to change.

Selector

Selector can be used to associate multiple channels in a thread and to listen for events.

Q: What are the benefits of Selector in NIO?

A:

  • You can manage channels with fewer threads.
  • Reduces the resource overhead of thread context switching.

Q: What types of channels are registered with Selector?

A: Non-blocking channels are supported. Channel to channel before the registration call. ConfigureBlocking (false) is set to a non-blocking. FileChannel, for example, cannot be registered; it is bound to block. Socketchannels can support non-blocking.

Q: What kinds of events are listened on when a Selector is registered, and what are the corresponding constants? (Oh, I hate memories…)

A: There are four types of listening events

  • Connect Successfully connects to one server, corresponding to the constant selectionkey.op_connect
  • Accept Is ready to receive incoming connections, corresponding to the constant selectionKey.op_ACCEPT
  • Read, which has data to Read, corresponds to the constant selectionkey.op_read
  • Write Receives data written to it, corresponding to the constant selectionKey. OP_WRITE

If you want to the channel to monitor various events, you can use “|” or the operator connects the constants.

int interestingSet = Selectionkey.OP_READ | Selectionkey.OP_WRITE;
Selectionkey key = channel.register(selector,interestingSet)
Copy the code
  • The SelectionKey represents the registration relationship between a particular channel object and a particular selector object

Q: What sets of selectionkeys are maintained by selectionKeys?

A: There are three kinds.

1. Registered key set (Registered key set)

The set of keys generated by all channels associated with a selector is called the set of registered keys. Not all registered keys are still valid. This collection is returned via the keys() method and may be empty. The set of registered keys is not directly modifiable; Trying to do so would trigger a Java. Lang. UnsupportedOperationException.

2. Selected key set

A subset of the set of registered keys. Each member of this collection is an operation that the channel associated with it is judged by the selector (in the previous selection operation) to be ready and contained in the interest collection of the key. This collection is returned (and possibly empty) by the selectedKeys() method. Do not confuse the set of selected keys with the Ready set. This is a collection of keys, each of which is associated with a channel that is ready for at least one operation. Each key has an embedded ready set, indicating that the associated channel is ready for action. Keys can be removed directly from the collection, but cannot be added. To a collection of selected key element is added will throw Java lang. UnsupportedOperationException.

3. Cancelled key set

A subset of the set of registered keys that contains the key for which the cancel() method was called (the key has been invalidated), but which has not yet been deregistered. This collection is a private member of the selector object and therefore cannot be accessed directly.

After registration, how to handle ready channels using selector:

1. Call the select() method to get ready channels, and return an int indicating how many channels are ready

2. Get selectedKeys from selector

3. The traverse selectedkeys

4. Check whether any events are ready in each SelectionKey.

5. If an event is ready, obtain the corresponding pipe from key. Do corresponding processing

Similarly, a thread is normally started to run the selector listener’s processing:

while(true) { int readyNum = selector.select(); if (readyNum == 0) { continue; } Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> it = selectedKeys.iterator(); while(it.hasNext()) { SelectionKey key = it.next(); If (key.iswritable ()) {// Acceptable connection} else if(key.isreadable ()) {else if(key.iswritable ()) {// Acceptable connection} it.remove(); }}Copy the code

The Q: select() method is actually a blocking method, meaning that it will wait until all channels have been polled. If you want to end select() early, what are the methods?

A: There are two ways:

Wakeup (), the select () method returns immediately.

Close (), just close the selector.

NIO is not blocking IO, but select() is blocking.

  • NIO non-blocking, actually, means that the IO is not blocking, that we’re not stuck at read(), we’re going to use selector to look for ready state, and if the state is OK.
  • The query operation takes time, so select() must check all channels to tell the result, so select is blocked.

other

Q: How to lock a file to ensure thread safety when multiple threads read and write the same file?

A: Use the lock function of FileChannel.

RandomAccessFile randFile = new RandomAccessFile(target, "rw"); FileChannel channel = randFile.getChannel(); FileLock FileLock = channel.lock(pos, size, shared); if (fileLock! =null) { do(); Try-catch filelock.release (); }Copy the code

Q: What buffer can I use if I need to read a very large file?

A: Use MappedByteBuffer. This buffer can interpret a large file as an array of bytes to be accessed (but does not actually load such a large array of bytes; the actual contents are stored in memory + virtual memory). A MappedByteBuffer is generated primarily by filechannel. map (mode, start position, region). You can then use put and get to handle bytes in the corresponding position.

int length = 0x8FFFFFF; // a byte for 1B, Try (FileChannel channel = filechannel.open (paths.get (" SRC /c.txt")), standardOpenOption.read, StandardOpenOption.WRITE);) { MappedByteBuffer mapBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, length); for(int i=0; i<length; i++) { mapBuffer.put((byte)0); } for(int i = length/2; i<length/2+4; I ++) {// Access system.out.println (mapbuffer.get (I)) like an array; }}Copy the code

Three modes:

  • Mapmode. READ_ONLY (read-only) : Attempts to modify the resulting buffer will result in ReadOnlyBufferException being thrown.
  • Mapmode.read_write (read/write) : Changes to the resulting buffer are written to the file, requiring a call to fore()
  • Mapmode. PRIVATE (PRIVATE) : Readable and writable, but the modified content is not written to the file, only changes to the buffer itself.

Q: ByteBuffer in NIO, how to convert it into the corresponding CharBuffer according to the correct encoding

A: Use the Decode function of Charset.

ByteBuffer byteBuffer = ... ; Charset charset = Charset.forName("UTF-8"); CharBuffer charBuffer = charset.decode(byteBuffer);Copy the code

For ByteBuffer, use charset.encode.

Click to follow, the first time to learn about Huawei cloud fresh technology ~