javaNIO learning notes (2)
Reference documents: http://tutorials.jenkov.com/java-nio/channels.html
Java NIO Channel
Compared with InputStream and OutputStream in traditional IO, the main difference is that the stream in traditional IO is unidirectional. But channels in NIO are readable and writable. And reading and writing can be done asynchronously. In addition, channels read or write data from the buffer
The main implemented pipeline types in the previous learning notes
-
FileChannel reads data from files and files
-
Datagram channel can read and write data on the network through UDP.
-
SocketChannel can read and write data on the network through TCP.
-
ServerSocketChannel allows you to listen for incoming TCP connections, just like a web server. Create a SocketChannel for each incoming connection.
These four classes can view the corresponding UML diagram in idea
FileChannel
First look at the following procedure
Read file data:
public class FileChannelPrc { public static void main(String[] args) throws IOException { // Create a random file of rw mode RandomAccessFile randomAccessFile =new RandomAccessFile("D:\\nioFile.txt", "rw"); // Get fileChinnel FileChannel fileChannel = randomAccessFile.getChannel(); // Set buffer size 48 ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = fileChannel.read(buf); while(bytesRead !=-1){ System.out.println("\nRead " + bytesRead); buf.flip(); while(buf.hasRemaining()){ System.out.print((char) buf.get()); } buf.clear(); bytesRead = fileChannel.read(buf); } randomAccessFile.close(); } } // Operation result: Hi, I am jimmy.
To execute the above program correctly, create the corresponding file in the local corresponding folder. What I write in the file is Hi, I am jimmy. Here you can see that it is read out and printed.
Then we change the contents of the file to Hi, I am jimmy. I am learning Java NIO. Hope I can hold it. When running the program, return the value
Read 48
Hi, I am jimmy. I am learning Java NIO. Hope I
Read 13
can hold it.
We can probably guess through the above test.
// Read the data to the buffer through fileChannel, and the return value is the number of bytes read by the buffer int bytesRead = fileChannel.read(buf); // Determine whether there is data in the buffer buf.hasRemaining() // Gets the first element of the current buffer buf.get() // Toggle buffer read / write mode buf.flip(); // Clear cache buf.clear();
Let's just look at the channel related guesses. Transformation procedure (the transformation part is as follows)
// Set buffer size ByteBuffer buf = ByteBuffer.allocate(48); ByteBuffer buf2 = ByteBuffer.allocate(48); int bytesRead = fileChannel.read(buf); int bytesRead2 = fileChannel.read(buf); System.out.println("bytesRead" + bytesRead + " bytesRead2" + bytesRead2);
At this time, you can see that bytesread = 16 bytesread2 = - 1 (file information Hi, I am jimmy.). Then we can draw a conclusion
fileChannel.read(buf); will flush the channel's data to the buffer instead of copying.
The following program uses fileChannel to write information to files
public class FileChannelPrc { public static void main(String[] args) throws IOException { ... // Write file // ByteBuffer buf2 = ByteBuffer.allocate(48); String newData = "do not worry, be happy Time:" + System.currentTimeMillis(); buf.clear(); buf.put(newData.getBytes()); while(buf.hasRemaining()) { buf.flip(); fileChannel.write(buf); } fileChannel.close(); randomAccessFile.close(); } }
View file, file text display
Hi, I am jimmy. do not worry, be happy Time: 1591970658685
It can be seen from the results that when fileChannel writes data, it adds write data at the end of the file instead of overwriting.
According to the above example, we will briefly summarize the simple use of fileChannel.
- Obtain the instance of fileChannel (note that public abstract class FileChannel is an abstract class). How to get it
You can use an instance of RandomAccessFile to get
- The method of reading data uses read to read the content to ByteBuffer. Of course, the use of ByteBuffer is also designed here, which will be summarized later
- The write process uses the write method to write the ByteBuffer information to the file.
- Of course, like traditional IO, you need to call close to close fileChannel
Next, take a look at the source code of fileChannel (this is also a memo. You can come back to take a look when you encounter related problems, which may help.)
// ----read method------- public abstract int read(ByteBuffer dst) throws IOException; // Read data from specified location public abstract int read(ByteBuffer dst, long position) throws IOException; public final long read(ByteBuffer[] dsts) throws IOException { return read(dsts, 0, dsts.length); } public abstract long read(ByteBuffer[] dsts, int offset, int length) throws IOException; // ------write method------ public abstract int write(ByteBuffer src) throws IOException; public abstract int write(ByteBuffer src, long position) throws IOException; public final long write(ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length); } public abstract long write(ByteBuffer[] srcs, int offset, int length) throws IOException; // ----open method - @ since 1.7 can get fileChannel public static FileChannel open(Path path, OpenOption... options) throws IOException { Set<OpenOption> set = new HashSet<OpenOption>(options.length); Collections.addAll(set, options); return open(path, set, NO_ATTRIBUTES); } public static FileChannel open(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException { FileSystemProvider provider = path.getFileSystem().provider(); return provider.newFileChannel(path, options, attrs); } // --- position -- // Get a new fileChannel public abstract FileChannel position(long newPosition) throws IOException; // Return the location of buffer read public abstract long position() throws IOException; // --- force ---- // Force the data of the channel to be written, and decide whether to write to the local disk storage according to the metaData public abstract void force(boolean metaData) throws IOException; // Returns the current size of this channel's file public abstract long size() throws IOException; // Intercept the data of specified length, and intercept the data of size from the beginning public abstract FileChannel truncate(long size) throws IOException;
Of course, there are some other methods, which will be supplemented later when it comes to use. The code at the time of test is attached here (not all, some API s can directly use the fragments of idea to view the results.)
public class FileChannelPrc { public static void main(String[] args) throws IOException { // Create a random file of rw mode RandomAccessFile randomAccessFile =new RandomAccessFile("D:\\nioFile.txt", "rw"); // Get fileChinnel FileChannel fileChannel = randomAccessFile.getChannel(); // fileChannel.position(); FileChannel fileChannel2 = fileChannel.truncate(10); // Set buffer size ByteBuffer buf = ByteBuffer.allocate(48); // int bytesRead = fileChannel.read(buf,10L); int bytesRead = fileChannel2.read(buf); // ByteBuffer buf2 = ByteBuffer.allocate(48); // int bytesRead = fileChannel.read(buf); /*int bytesRead2 = fileChannel.read(buf); System.out.println("bytesRead" + bytesRead + " bytesRead2" + bytesRead2);*/ while(bytesRead !=-1){ System.out.println("Read " + bytesRead); buf.flip(); while(buf.hasRemaining()){ System.out.print((char) buf.get()); } buf.clear(); // bytesRead = fileChannel.read(buf); bytesRead = fileChannel2.read(buf); } // Write file // ByteBuffer buf2 = ByteBuffer.allocate(48); /* String newData = "do not worry, be happy Time:+ System.currentTimeMillis(); buf.clear(); buf.put(newData.getBytes()); while(buf.hasRemaining()) { buf.flip(); fileChannel.write(buf); }*/ fileChannel.close(); randomAccessFile.close(); } }
SocketChannel and ServerSocketChannel
Socketchannel is a channel used to process TCP network sockets. There are two ways to get socketchannel
- You can get an instance directly by using open()
- Get through ServerSocketChannel
SocketChannel socketChannel = SocketChannel.open();
The ServerSocketChannel is similar to the ServerSocket in the standard Java network. It is a channel that can listen for incoming TCP connections
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
no talk,show code
package jniolearn.channel; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; /** * @Author: jimmy * @Date: 2020/6/13 15:03 * @Description: * * Understand as server */ public class ServerSocketChannelPrc { public static void main(String[] args) throws IOException { // Get instance ServerSocketChannel server = ServerSocketChannel.open(); // Binding ip and port server.socket().bind(new InetSocketAddress("127.0.0.1",2999)); //Set to non blocking mode server.configureBlocking(false); // Get SocketChannel while(true){ SocketChannel serverChannel = server.accept(); if(serverChannel != null) { ByteBuffer buf = ByteBuffer.allocate(512); int byteRead = serverChannel.read(buf); StringBuilder req = new StringBuilder(); buf.flip(); while(buf.hasRemaining()){ req.append((char) buf.get()); } buf.clear(); System.out.println("Message from client" + req); buf.put("hi,this is jimmy. be happy ".getBytes()); buf.flip(); serverChannel.write(buf); // serverChannel.close(); } } } } package jniolearn.channel; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; /** * @Author: jimmy * @Date: 2020/6/13 12:04 * @Description: * * It can be understood as client */ public class SocketChannelPrc { /** * For convenience, throw the exception directly here. The actual development needs to catch the exception * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // Get an instance of SocketChannel SocketChannel client = SocketChannel.open(); /** * Connect to the server. The parameter object passed in is SocketAddress * Check the source code to find an implementation class InetSocketAddress construction method public InetSocketAddress(String hostname, int port) * I'm familiar with this structure, * * Connecting services 127.0.0.1 and 2999 ports */ client.connect(new InetSocketAddress("127.0.0.1",2999)); // A channel requires a buffer ByteBuffer buf = ByteBuffer.allocate(512); buf.put("hi, jimmy,this is client.".getBytes()); // Switch between read and write mode buf.flip(); // Write data to server client.write(buf); // Clear the buffer, which is equivalent to resetting the buffer to read mode buf.clear(); int byteRead = client.read(buf); buf.flip(); StringBuilder stringBuffer=new StringBuilder(); while (buf.hasRemaining()){ stringBuffer.append((char) buf.get()); } buf.clear(); System.out.println("Data received from the server:"+stringBuffer); // Close socketChannel client.close(); } }
Start ServerSocketChannel on the server, and then U starts SocketChannel. The return result is as follows:
hi, jimmy,this is client Data received from the server: hi,this is jimmy. be happy
Generally speaking, it's not much different from fileChannel. Basically, you need to have an open channel first (there's a way to get whether it's open or not). The corresponding buffer is then used to write data from the channel to the buffer or read data from the buffer. (the buffer related methods will be studied later.). However, some special points should be noted: configureBlocking() a method of socketchannel indicates whether the socketchannel 'serversocketchannel is blocked or non blocked. When learning the selector, you should supplement it. Of course, the above program is not perfect, and an error will be reported when the receiving buffer is not large enough. You can change the code to see.
DatagramChannel
DatagramChannel is similar to DatagramSocket class of java network programming; UDP is used for network transmission
Similarly, you can use the open method to get an instance
package jniolearn.channel; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; /** * @Author: jimmy * @Date: 2020/6/13 17:32 * @Description: * server */ public class DatagramChannelPrcS { public static void main(String[] args) throws IOException { DatagramChannel s = DatagramChannel.open(); s.bind(new InetSocketAddress("127.0.0.1",3999)); ByteBuffer buf = ByteBuffer.allocate(48); s.receive(buf); buf.clear(); while(buf.hasRemaining()){ System.out.print((char)buf.get()); } } } package jniolearn.channel; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; /** * @Author: jimmy * @Date: 2020/6/13 17:26 * @Description: * client */ public class DatagramChannelPrc { public static void main(String[] args) throws IOException { DatagramChannel channel = DatagramChannel.open(); // Bind port // channel.bind(new InetSocketAddress(3999)); ByteBuffer buf = ByteBuffer.allocate(48); buf.put("datagrameChannel info".getBytes()); // Datagram channel does not need to use this method // channel.write(buf); buf.flip(); int a = channel.send(buf,new InetSocketAddress("127.0.0.1",3999)); channel.close(); } }
It is relatively simple to use. The server can directly use bind method to bind port and ip. The client sends the data directly from the buffer to the server. There is no guarantee whether the message is sent successfully or received successfully. The send message is sent through the send method. The change method returns an int value, indicating the number of bytes successfully sent:
So one of the tails of this learning is about the difference and application between blocking mode and non blocking mode. This is a supplementary study after learning other classes
buf = ByteBuffer.allocate(48);
buf.put("datagrameChannel info".getBytes());
//Datagram channel does not need to use this method
// channel.write(buf);
buf.flip();
int a = channel.send(buf,new InetSocketAddress("127.0.0.1",3999));
channel.close();
}
}
It is relatively simple to use. The server can directly use bind method to bind port and ip. The client sends the data directly from the buffer to the server. There is no guarantee whether the message is sent successfully or received successfully. The send message is sent through the send method. The change method returns an int value, indicating the number of bytes successfully sent: So the tail of this learning is about the difference and application between blocking mode and non blocking mode. This is a supplementary study after learning other classes