Implementation Types of Java NIO Channels

file channel

A FileChannel in Java NIO is a channel that connects to a file. Files can be read and written through the file channel. 

FileChannel cannot be set to non-blocking mode, it always runs in blocking mode. 

Open FileChannel 

Before a FileChannel can be used, it must be opened. However, we cannot open a FileChannel directly, we need to obtain a FileChannel instance by using an InputStream, OutputStream or RandomAccessFile. Here is an example of opening a FileChannel via RandomAccessFile: 

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");  
FileChannel inChannel = aFile.getChannel();

Read data from FileChannel 

Call one of several read() methods to read data from the FileChannel. Such as: 

ByteBuffer buf = ByteBuffer.allocate(48);  
int bytesRead = inChannel.read(buf);  
First, allocate a Buffer. Data read from FileChannel will be read into Buffer. 

Then, call the FileChannel.read() method. This method reads data from FileChannel into Buffer. The int value returned by the read() method indicates how many bytes were read into the Buffer. If it returns -1, it means the end of the file is reached.  

Write data to FileChannel 
Use the FileChannel.write() method to write data to FileChannel. The parameter of this method is a Buffer. Such as: 

String newData = "New String to write to file..." + System.currentTimeMillis();  
  
ByteBuffer buf = ByteBuffer.allocate(48);  
buf.clear();  
buf.put(newData.getBytes());  
  
buf.flip();  
  
while(buf.hasRemaining()) {  
    channel.write(buf);  
}  

Note that FileChannel.write() is called in a while loop. Because there is no guarantee how many bytes the write() method can write to the FileChannel at a time, the write() method needs to be called repeatedly until there are no more bytes in the Buffer that have not been written to the channel.

Closing the FileChannel 
You must close the FileChannel when you are done using it. Such as: 

channel.close();  
The position method 
of FileChannel may sometimes need to read/write data in a specific position of the FileChannel. The current position of the FileChannel can be obtained by calling the position() method. 
The current position of the FileChannel can also be set by calling the position(long pos) method. 

Here are two examples:

long pos = channel.position();  
channel.position(pos +123);  
If you set the position after the end-of-file character and then attempt to read data from the file channel, the read method will return -1 - the end-of-file flag. 
If you set the position after the end-of-file character, and then write data to the channel, the file will be stretched to the current position and the data will be written. This can lead to "file holes", gaps between data written in physical files on disk.

 The size method of FileChannel 

The size() method of a FileChannel instance will return the size of the file associated with the instance. Such as: 

long fileSize = channel.size();  
truncate method of FileChannel 

A file can be truncated using the FileChannel.truncate() method. When intercepting a file, the part after the specified length in the file will be deleted. Such as:  

channel.truncate(1024);  
This example truncates the first 1024 bytes of the file. 
The force method of 
FileChannel The FileChannel.force() method forces the data in the channel that has not been written to the disk to be written to the disk. For performance reasons, the operating system caches data in memory, so there is no guarantee that data written to FileChannel will be written to disk immediately. To ensure this, the force() method needs to be called. 
The force() method has a boolean parameter that indicates whether to write file metadata (permission information, etc.) to disk at the same time. 
The following example forces both file data and metadata to be written to disk: 
channel.force(true);  


Socket channel

A SocketChannel in Java NIO is a channel that connects to a TCP network socket. A SocketChannel can be created in the following 2 ways: 

  • Open a SocketChannel and connect to some server on the internet.
  • A SocketChannel is created when a new connection arrives on the ServerSocketChannel.

Open SocketChannel 

SocketChannel socketChannel = SocketChannel.open();  
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));  

close SocketChannel 

socketChannel.close();  
Read data from SocketChannel 
ByteBuffer buf = ByteBuffer.allocate(48);  
int bytesRead = socketChannel.read (buf);  
First, allocate a Buffer. The data read from SocketChannel will be put into this Buffer. 

Then, call SocketChannel.read(). This method reads data from SocketChannel into Buffer. The int value returned by the read() method indicates how many bytes were read into the Buffer. If -1 is returned, the end of the stream has been read (the connection is closed). 

write to SocketChannel 

String newData = "New String to write to file..." + System.currentTimeMillis();  
  
ByteBuffer buf = ByteBuffer.allocate(48);  
buf.clear();  
buf.put(newData.getBytes());  
  
buf.flip();  
  
while(buf.hasRemaining()) {  
    channel.write(buf);  
}  

Note that the call to the SocketChannel.write() method is in a while loop. The Write() method cannot guarantee how many bytes can be written to the SocketChannel. So, we call write() repeatedly until the Buffer has no more bytes to write.

non-blocking mode 

SocketChannel can be set to non-blocking mode (non-blocking mode). After setting, you can call connect(), read() and write() in asynchronous mode.

connect() 
If the SocketChannel is in non-blocking mode and connect() is called at this time, this method may return before the connection is established. To determine whether the connection is established, the finishConnect() method can be called. like this:

ocketChannel.configureBlocking(false);  
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));  
  
while(! socketChannel.finishConnect() ){  
    //wait, or do something else...  
}

write() 

In non-blocking mode, the write() method may return without writing anything. So you need to call write() in a loop. There have been examples before, so I won't repeat them here. 

read() 

In non-blocking mode, the read() method may return without reading any data. So pay attention to its int return value, which will tell you how many bytes were read. 

Non-blocking mode and selectors 

Non-blocking mode works better with selectors, by registering one or more SocketChannels with the Selector, you can ask the selector which channels are ready for reading, writing, etc. The use of Selector and SocketChannel will be discussed in detail later.


ServerSocket channel 

A ServerSocketChannel in Java NIO is a channel that can listen for incoming TCP connections, just like a ServerSocket in standard IO. The ServerSocketChannel class is in the java.nio.channels package.

 
 
//Open ServerSocketChannel by calling ServerSocketChannel.open() method ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(9999)); while(true){ SocketChannel socketChannel = serverSocketChannel.accept() ; //do something with socketChannel... } //Close ServerSocketChannel.serverSocketChannel.close() by calling ServerSocketChannel.close() method; 

Listen for new incoming connections 

Listen for incoming connections via the ServerSocketChannel.accept() method. When the accept() method returns, it returns a SocketChannel containing the new incoming connection. Therefore, the accept() method will block until a new connection arrives. Usually instead of just listening for one connection, the accept() method is called in a while loop. As in the following example: 

while(true){  
    SocketChannel socketChannel = serverSocketChannel.accept();  
  
    //do something with socketChannel...  
}  

Of course, other exit criteria than true can also be used in the while loop. 

Non-blocking mode 
ServerSocketChannel can be set to non-blocking mode. In non-blocking mode, the accept() method will return immediately, or null if there is no new incoming connection. Therefore, it is necessary to check whether the returned SocketChannel is null. Such as:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  
  
serverSocketChannel.socket().bind(new InetSocketAddress(9999));  
serverSocketChannel.configureBlocking(false);  
  
while(true){  
    SocketChannel socketChannel = serverSocketChannel.accept();  
  
    if(socketChannel != null){  
        //do something with socketChannel...  
    }  
}  


Datagram channel 

The DatagramChannel in Java NIO is a channel that can send and receive UDP packets. Because UDP is a connectionless network protocol, it cannot be read and written like other channels. It sends and receives packets. 

Open DatagramChannel 

DatagramChannel channel = DatagramChannel.open();  
channel.socket().bind(new InetSocketAddress(9999));  
The DatagramChannel opened by this example can receive packets on UDP port 9999. 

Receive data 

ByteBuffer buf = ByteBuffer.allocate(48);  
buf.clear();  
channel.receive(buf);  

The receive() method will copy the content of the received data packet to the specified Buffer. If the Buffer cannot hold the received data, the excess data will be discarded.

send data

String newData = "New String to write to file..." + System.currentTimeMillis();  
  
ByteBuffer buf = ByteBuffer.allocate(48);  
buf.clear();  
buf.put(newData.getBytes());  
buf.flip();  
  
int bytesSent = channel.send(buf, new InetSocketAddress("jenkov.com", 80));
This example sends a string of characters to the "jenkov.com" server on UDP port 80. Since the server is not monitoring this port, nothing will happen. It also doesn't notify you if the outgoing packet has been received, since UDP doesn't have any guarantees about data delivery.  


connect to a specific address

A DatagramChannel can be "connected" to a specific address in the network. Since UDP is connectionless, connecting to a specific address does not create a real connection like a TCP channel does. Instead, lock the DatagramChannel so that it can only send and receive data from a specific address.

channel.connect(new InetSocketAddress("jenkov.com", 80));  
When connected, the read() and write() methods can also be used, just as with traditional channels. It's just that there are no guarantees in terms of data transfer. Here are a few examples:  
int bytesRead = channel.read(buf);  
int bytesWritten = channel.write(but);  


Pipe

A Java NIO pipe is a one-way data connection between 2 threads. Pipe has a source channel and a sink channel. Data will be written to the sink channel and read from the source channel. 


Create pipeline

Pipe pipe = Pipe.open();  
write data to the pipe

To write data to the pipe, you need to access the sink channel. like this:   

Pipe.SinkChannel sinkChannel = pipe.sink();  

Write data to the SinkChannel by calling the write() method of the SinkChannel, like this: 

String newData = "New String to write to file..." + System.currentTimeMillis();  
ByteBuffer buf = ByteBuffer.allocate(48);  
buf.clear();  
buf.put(newData.getBytes());  
  
buf.flip();  
  
while(buf.hasRemaining()) {  
    sinkChannel.write(buf);
}  
read data from pipe 

To read data from the pipe, you need to access the source channel, like this: 

Pipe.SourceChannel sourceChannel = pipe.source();  

Call the read() method of the source channel to read the data, like this: 

ByteBuffer buf = ByteBuffer.allocate(48);  
  
int bytesRead = inChannel.read(buf);  
The int value returned by the read() method tells us how many bytes were read into the buffer. 





Guess you like

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