Detailed explanation of Java NIO (1)

1. Description of basic concepts

1.1 I / O

I/O is input and output, which is an excuse between the computer and the outside world. The actual subject of IO operations is the operating system. In java programming, IO is generally handled in a stream manner. All IO is regarded as the movement of a single byte, and one byte is moved at a time through the stream object. Stream IO is responsible for converting objects to bytes and then back to objects.

For Java IO related knowledge, please refer to my other article: Java IO Detailed Explanation

1.2 What is NIO

NIO is New IO, this library was only introduced in JDK1.4. NIO and IO have the same function and purpose, but the implementation methods are different. NIO mainly uses blocks , so the efficiency of NIO is much higher than that of IO.

Two sets of NIO are provided in the Java API, one is for standard input and output NIO , and the other is for network programming NIO . This article focuses on standard NIO. For network programming NIO, see Java NIO Detailed Explanation (2) .

1.3 Comparison of streams and blocks

The biggest difference between NIO and IO is the way data is packaged and transmitted. IO processes data in a stream , while NIO processes data in blocks .

Stream-oriented IO processes data one byte at a time, one input stream producing one byte and one output stream consuming one byte. It is very easy to create filters for streaming data, chaining several filters in order to process the data is very convenient and simple, but stream-oriented IO is usually very slow.

Block-oriented IO systems process data in blocks. Each operation produces or consumes a block of data in one step. Blockwise is much faster than streamwise, but block-oriented IO lacks the elegance and simplicity of stream-oriented IO.

2. NIO basics

Buffer and Channel are the core objects in standard NIO (there is also a Selector core object in network NIO, please refer to Java NIO Detailed Explanation (2) for details ), and they are used in almost every IO operation.

Channel is a simulation of the flow in the original IO, any source and destination data must pass through a Channel object. A Buffer is essentially a container object, and all objects sent to the Channel must first be placed in the Buffer; similarly, any data read from the Channel must be read into the Buffer.

2.1 About Buffer

Buffer is an object that contains some data to be written or read. In NIO, data is put into buffer objects, while in IO, data is directly written or read to Stream objects. The application cannot directly read and write to the Channel, but must do it through the Buffer , that is, the Channel reads and writes the data through the Buffer.

In NIO, all data is processed with Buffer, which is the transfer pool for NIO to read and write data. A Buffer is essentially an array, usually a byte of data, but can be other types of arrays as well. But a buffer is not just an array, the important thing is that it provides structured access to the data, but also keeps track of the read and write progress of the system.

Using Buffer to read and write data generally follows the following four steps:

  1. Write data to Buffer;
  2. call flip() method;
  3. Read data from Buffer;
  4. Call the clear() method or the compact() method.

When writing data to the Buffer, the Buffer will record how much data was written. Once the data is to be read, the Buffer needs to be switched from write mode to read mode by flip() method . In read mode, all data previously written to the Buffer can be read.

Once all the data has been read, the buffer needs to be emptied so that it can be written again. There are two ways to clear the buffer: call the clear() or compact() method. The clear() method clears the entire buffer. The compact() method will only clear data that has already been read. Any unread data is moved to the beginning of the buffer, and newly written data is placed after the unread data in the buffer.

Buffers are mainly as follows:1

2.3 About Channel

Channel is an object through which data can be read and written. Think of it as a stream in IO. But it has some differences compared to streams:

  1. Channels are bidirectional, both read and write, while streams are unidirectional
  2. Channel can perform asynchronous read and write
  3. Reading and writing to Channel must pass through the buffer object

As mentioned above, all data is handled through a Buffer object, so you never write bytes directly to a Channel, instead you write data to a Buffer; likewise, you don't write bytes from a Channel Instead, read the data from the Channel into the Buffer, and then get the byte from the Buffer.

Because Channels are bidirectional, Channels better reflect the reality of the underlying operating system than Streams. In the Unix model in particular, the underlying operating system is often bidirectional.2

Channels in Java NIO mainly have the following types:

  • FileChannel: for reading data from a file
  • DatagramChannel: read and write UDP network protocol data
  • SocketChannel: read and write TCP network protocol data
  • ServerSocketChannel: can listen for TCP connections

3. From theory to practice: reading and writing in NIO

Read and write in IO correspond to data and Stream, and read and write in NIO correspond to channels and buffers. Read from the channel in NIO: create a buffer, and then let the channel read data into the buffer. NIO writes data to the channel: create a buffer, fill it with data, and then let the channel use that data to perform the write.

3.1 Reading from a file

We already know that in the NIO system, whenever you perform a read operation, you are reading from the Channel, and you are not reading data directly from the Channel, because all data must be encapsulated in Buffer, so you should Is to read data from Channel to Buffer.

Therefore, if reading data from a file, the following three steps are required:

  1. Get Channel from FileInputStream
  2. Create Buffer
  3. Read data from Channel to Buffer

Let's take a look at the specific process:
Step 1: Get the channel

FileInputStream fin = new FileInputStream( "readandshow.txt" );
FileChannel fc = fin.getChannel();  
123

Step 2: Create a buffer

ByteBuffer buffer = ByteBuffer.allocate( 1024 );
12

Step 3: Read data from channel to buffer

fc.read( buffer );
12

3.2 Write data to file

Similar to reading data from a file, the
first step: get a channel

FileOutputStream fout = new FileOutputStream( "writesomebytes.txt" );
FileChannel fc = fout.getChannel();
123

Step 2: Create a buffer, put data into the buffer

ByteBuffer buffer = ByteBuffer.allocate( 1024 );

for (int i=0; i<message.length; ++i) {
 buffer.put( message[i] );
}
buffer.flip();
1234567

Step 3: Write the buffer data to the channel

fc.write( buffer );
12

3.3 Combination of reading and writing

CopyFile is a very good example of the combination of reading and writing. We will let everyone experience the operation process of NIO through the strength of CopyFile. CopyFile performs three basic operations: creates a Buffer, then reads data from the source file into the buffer, and then writes the buffer to the destination file.

/**
 * 用java NIO api拷贝文件
 * @param src
 * @param dst
 * @throws IOException
 */
public static void copyFileUseNIO(String src,String dst) throws IOException{
    //声明源文件和目标文件
            FileInputStream fi=new FileInputStream(new File(src));
            FileOutputStream fo=new FileOutputStream(new File(dst));
            //获得传输通道channel
            FileChannel inChannel=fi.getChannel();
            FileChannel outChannel=fo.getChannel();
            //获得容器buffer
            ByteBuffer buffer=ByteBuffer.allocate(1024);
            while(true){
                //判断是否读完文件
                int eof =inChannel.read(buffer);
                if(eof==-1){
                    break;  
                }
                //重设一下buffer的position=0,limit=position
                buffer.flip();
                //开始写
                outChannel.write(buffer);
                //写完要重置buffer,重设position=0,limit=capacity
                buffer.clear();
            }
            inChannel.close();
            outChannel.close();
            fi.close();
            fo.close();
}     
12345678910111213141516171819202122232425262728293031323334

4. Points to pay attention to

There are three places to pay attention to in the above program

4.1 Check Status

When there is no more data, the copy is completed, and the read() method will return -1 at this time, and we can judge whether the read is completed according to this method.

int r= fcin.read( buffer );
if (r==-1) {
     break;
     }
12345

4.2 The flip and clear methods of the Buffer class

Three variables that control the state of the buffer

  • position: keeps track of how much data has been written or read, it points to where the next byte comes from
  • limit: Indicates how much data can be fetched or how much space can be written, and its value is less than or equal to capacity.
  • capacity: represents the maximum capacity of the buffer. Generally, when a new buffer is created, the value of limit and the value of capacity are equal by default.

The two methods flip and clear are used to set these values.

flip method

Let's first look at the source code of flip:

public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
 }

3

In the FileCopy program above, after writing the data and before reading the data, we call the buffer.clear();method which resets the buffer to receive more bytes. The image above shows the state of the buffer after calling clear().

Please indicate the source of the reprint, the original link: http://blog.csdn.net/suifeng3051/article/details/48160753

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324778349&siteId=291194637