Channel classification in Java NIO:

  • FileChannel
  • SocketChannel
  • ServerSocketChannel
  • DatagramChannel

FileChannel: Used to read and write files from or to a disk.

SocketChannel: Reads data from or writes data to the Channel of the TCP connection used for the Socket

ServerSocketChannel: The ServerSocketChannel listens for TCP connections. After the server listens for connections, it creates a SocketChannel for each request

DatagramChannel: used for reading and writing UDP data

Next, we will introduce them respectively.

FileChannel

Mainly used for operating documents, nonsense not to say, see examples directly.

TXT file, containing shDEQuanZhanBiJi

Input a FileInputStream

The FileChannel input stream is used to read data from the FileChannel, for example, by entering a specified file into the FileChannel to retrieve the file’s contents.

public static void main(String[] args) throws IOException {
  // Create an input stream
  FileInputStream fileInputStream = new FileInputStream("test-file.txt");
  // Get the channel from the input stream
  FileChannel fileChannel = fileInputStream.getChannel();

  // Prepare ByteBuffer
  ByteBuffer buffer = ByteBuffer.allocate(16);
  // Read the channel data of the input stream into buffer
  fileChannel.read(buffer);

  // Simply print the contents of the buffer
  printBuffer(buffer); // shDEQuanZhanBiJi
}
Copy the code

The ByteBuffer is the medium through which a channel reads and writes data. To read data from a channel (as in the above example), the data needs to be read into a ByteBuffer; In the same way, to write data to a channel, you need to write data to a ByteBuffer (we’ll talk about output streams below).

If you are not familiar with ByteBuffer, you can take a look at the code for printBuffer

Output FileOutputStream

As the name implies, a FileChannel outputs data, such as writing data to a disk file. Here’s an example:

public static void main(String[] args) throws IOException {
  // Specify the name of the file to be generated
  String generateFileName = "generate-file.txt";
  // Create an output stream
  FileOutputStream fileOutputStream = new FileOutputStream(generateFileName);
  // Get the channel from the output stream
  FileChannel fileChannel = fileOutputStream.getChannel();

  // Prepare ByteBuffer and write data to it
  ByteBuffer buffer = ByteBuffer.allocate(16);
  buffer.put("shDEQuanZhanBiJi".getBytes(StandardCharsets.UTF_8));

  // Read the channel data of the input stream into buffer
  fileChannel.write(buffer);
  fileChannel.close();
}
Copy the code

The corresponding comments have been posted on the corresponding code, and the details will not be covered here. The only thing of concern is that the call to write the file to disk is also the ByteBuffer passed in first.

Well, when you’re done running the code you’ll find that even though the file was generated, it’s empty… This actually involves the familiarity of ByteBuffer, which is a pit to bury.

If you don’t know why the file is empty, check out the ByteBuffer article above.

This is because ByteBuffer is created in write mode by default and cannot be read by position and limit. So before calling write, we need to switch ByteBuffer to read mode first. The complete code is as follows:

public static void main(String[] args) throws IOException {
  // Specify the name of the file to be generated
  String generateFileName = "generate-file.txt";
  // Create an output stream
  FileOutputStream fileOutputStream = new FileOutputStream(generateFileName);
  // Get the channel from the output stream
  FileChannel fileChannel = fileOutputStream.getChannel();

  // Prepare ByteBuffer and write data to it
  ByteBuffer buffer = ByteBuffer.allocate(16);
  buffer.put("shDEQuanZhanBiJi".getBytes(StandardCharsets.UTF_8));

  // Set ByteBuffer to read mode
  buffer.flip();
  // Read the channel data of the input stream into buffer
  fileChannel.write(buffer);
  
  fileChannel.close();
}
Copy the code

As you can see, the file is generated and the content is available:

However, the above two can only be written or read. FileInputStream, for example if you stubbornly Dui data into the channel and program finally throws NonWritableChannelException abnormalities, can’t tell you this thing to write.

Is there an implementation that can write, read and sing? Of course there is. That’s RandomAccessFile.

For the record, the write call is not immediately written to disk, but can also be stored in the operating system cache. If the disk needs to be flushed immediately, call channel.force(true); Can.

RandomAccessFile

How does it work? It’s pretty much the same as the other two:

public static void main(String[] args) throws IOException {
  // Specify the name of the file to be generated
  String targetFileName = "target-file.txt";
  // Create RandomAccessFile with read (r) and write (w) permissions
  RandomAccessFile accessFile = new RandomAccessFile(targetFileName, "rw");
  FileChannel fileChannel = accessFile.getChannel();

  // Create ByteBuffer and write data
  ByteBuffer buffer = ByteBuffer.allocate(16);
  buffer.put("shDEQuanZhanBiJi".getBytes(StandardCharsets.UTF_8));
  // Switch to read mode of buffer
  buffer.flip();
  // Call write to write buffer data to channel, channel writes data to disk file
  fileChannel.write(buffer);

  // Empty the buffer
  buffer.clear();
  // Read the data previously written to channel into buffer
  fileChannel.read(buffer);

  // Prints the contents of buffer
  printBuffer(buffer);

  fileChannel.close();
}
Copy the code

As a result, a file named target-file. TXT is generated with the name shDEQuanZhanBiJi. And the console will print out the shDEQuanZhanBiJi that was previously written to the channel.

As always, the details are in the notes. Note that new RandomAccessFile(targetFileName, “rw”); In the rw. It is also stated in the comment, which stands for granting readable and writable permissions.

It’s also worth noting that you can’t say change rw to w.

You can’t play it that way, because it’s a pure string match, and there’s only so much you can do:

As you can see, r is essential… :

  • rCan only read
  • rwBoth canread, also canwrite
  • rwsrwdFunction andrwIt’s basically the same, readable, writable. The only difference is that they force every change to disk, andrwsThe operating system will also brush the metadata of the file, which reflects that the update time of the file will be updated, andrwdThe metadata of the file will not be flushed

Two SocketChannel

Since these two are responsible for connection transmission, the other is responsible for connection monitoring, so put together. Here’s what we’re going to do in this section:

But in order for you to run it directly, instead of reading from disk files on the client side, you use ByteBuffer. You can run it and try to load it from disk yourself. Let’s start with the server code:

ServerSocketChannel

public static void main(String[] args) throws IOException {
  // Open a ServerSocketChannel
  ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
  // Bind port 8080
  serverSocketChannel.bind(new InetSocketAddress(8080));

  // Start accepting client connections
  SocketChannel socketChannel = serverSocketChannel.accept();
  // The connection is successfully obtained
  System.out.printf("socketChannel %s connected\n", socketChannel);
  // Prepare ByteBuffer to read data from socketChannel
  ByteBuffer buffer = ByteBuffer.allocate(16);

  // Start reading data
  System.out.println("before read");
  int read = socketChannel.read(buffer);
  System.out.printf("read complete, read bytes length: %s \n", read);

  printBuffer(buffer);
}
Copy the code

Here we are using the default blocking mode in Java NIO, just as a cover. If you want ServerSocketChannel to enter non-blocking mode, you can call it after opening:

serverSocketChannel.configureBlocking(false);
Copy the code

Because we are here in a blocking mode, so in the code to run to serverSocketChannel. The accept (); Is blocked until a client comes to establish a connection. Similarly, the read method blocks, and if the client never writes data, the server will always block on read.

SocketChannel

Give the code directly first:

public static void main(String[] args) throws IOException {
  // Open a SocketChannel
  SocketChannel socketChannel = SocketChannel.open();
  // Connect to port 8080 of localhost
  socketChannel.connect(new InetSocketAddress("localhost".8080));

  / / for ByteBuffer
  ByteBuffer buffer = ByteBuffer.allocate(16);
  buffer.put(Charset.defaultCharset().encode("test"));

  // Switch buffer to read mode & write data to channel
  buffer.flip();
  socketChannel.write(buffer);
}
Copy the code

Start the server and then the client. You can see that the console on the server side has the following output:

[connected socketChannel Java nio. Channels. A socketChannel local = / 127.0.0.1: remote = 8080/127.0.0.1:64373] connected before read read complete, read bytes length: 4 BUFFER VALUE: testCopy the code

Datagram

This one is a bit simpler, starting with the client code:

public static void main(String[] args) throws IOException {
  DatagramChannel datagramChannel = DatagramChannel.open();

  // Build buffer data
  ByteBuffer buffer = ByteBuffer.allocate(16);
  buffer.put(Charset.defaultCharset().encode("test"));

  // Switch to read mode of buffer
  buffer.flip();
  datagramChannel.send(buffer, new InetSocketAddress("localhost".8080));
}
Copy the code

Then there is the server:

public static void main(String[] args) throws IOException {
  DatagramChannel datagramChannel = DatagramChannel.open();
  datagramChannel.bind(new InetSocketAddress(8080));

  ByteBuffer buffer = ByteBuffer.allocate(16);
  datagramChannel.receive(buffer);

  printBuffer(buffer);
}
Copy the code

Welcome to wechat search and follow [SH full stack Notes]. If you think this article is helpful to you, please click a like, close a note, share a share and leave a message.