Show the operation of a NIO, FileChannel

definition

In JDK 1.4 defines a new API, the New IO, IO API standard have different ways of working, NIO core components include Channel (channel), Buffer (buffer), Selectors (selector).

Traditional and IO is byte character stream operations are blocking, based on the NIO and Channel Buffer, are non-blocking, the event listener Selector for a plurality of channels. Single thread can monitor a plurality of data channels.

Channel和Buffer

IO Channel and similar flow in, but the flow is unidirectional, InputStream only input can not be output, OutputStream you can not do input output, while Channel on the powerful, either output, they can enter, Dangdie and as a mother's.

The main achievement Channel are:
FileChannel: read and write data files
DatagramChannel: UDP data read and write
SocketChannel: TCP read and write data, the general client implementation
ServerSocketChannel: general server implementation.

FileChannel

FileChannel Read Write rely ByteBuffer to complete, call read to read data in ByteBuffer, ByteBuffer call to write the data written back to the file.

Written to a file using the data packed into the byte ByteBuffer.wrap ByteBuffer, Charset class may be invoked to encode a string, returns ByteBuffer object.

private static void test0(String path) {
   try {
       FileOutputStream fileOutputStream = new FileOutputStream(path);
       FileChannel channel = fileOutputStream.getChannel();
       
       byte[] bytes ="abc听风逝夜def".getBytes();
       ByteBuffer byteBuffer =ByteBuffer.wrap(bytes);
       channel.write(byteBuffer);
         channel.write(Charset.forName("utf-8").encode("abc听风逝夜def"));
   }catch (IOException e){
        e.toString();
   }
}

Read a file from the FileInputStream get FileChannel, otherwise it will report java.nio.channels.NonReadableChannelExceptionan exception. Read the operation is more learned. First, the definition of a buffer, the read buffer, read () returns the size of read using the read method, if it returns -1 indicates read play. Get byte data read by the array () method. Finally, clear the cache data has been read, prepare for the next read.

 try {
     FileInputStream fileInputStream = new FileInputStream(path);
     FileChannel channel = fileInputStream.getChannel();
     ByteBuffer byteBuffer =ByteBuffer.allocate(1024);
     while (channel.read(byteBuffer)>0){
         System.out.println(new String(byteBuffer.array()));
         byteBuffer.clear();
     }
 }catch (IOException e){
     e.toString();
 }

However, these codes will happen.
Here Insert Picture Description
There will be a lot of empty data is output, because ByteBuffer size is 1024, and the file size is 18 bytes, the rest of the 1024-18 no place to store things. The solution is simple, ByteBuffer is intercepted in the first N data.

private static void test1(String path) {
 try {
     FileInputStream fileInputStream = new FileInputStream(path);
     FileChannel channel = fileInputStream.getChannel();
     ByteBuffer byteBuffer =ByteBuffer.allocate(1024);
     int post=0;
     while (( post=channel.read(byteBuffer))>0){
         byte[] data =new byte[post];
         System.arraycopy(byteBuffer.array(),0,data,0,post);
         System.out.println(new String(data));
         byteBuffer.clear();
     }
 }catch (IOException e){
     e.toString();
 }
}

There is also a Sao operations, which have a scholarship, flip () method and the limit, the following will say.

private static void test1(String path) {
    try {
     FileInputStream fileInputStream = new FileInputStream(path);
     FileChannel channel = fileInputStream.getChannel();
     ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
     while (channel.read(byteBuffer) > 0) {
         byteBuffer.flip();
         int limit = byteBuffer.limit();
         byte[] datas = new byte[limit];
         byteBuffer.get(datas);
         System.out.println(new String(datas));
         byteBuffer.clear();
     }
 } catch (IOException e) {
     e.toString();
 }

flip()

ByteBuffer There are two modes, one to write a to read.

Write, inside pos property with the movement of the write size is equivalent to a pointer, the following code, a byte as put, pos 1 will be moved back, but when putInt, 4-byte move because int is 4 bytes, other types, too, will move putLong 8 bytes. Internal limit = capacity. When the size of the put exceeds limit, an error.

 ByteBuffer byteBuffer =ByteBuffer.allocate(100);
 System.out.println(byteBuffer);
 byteBuffer.put("1".getBytes());
 System.out.println(byteBuffer);
 byteBuffer.putInt(1);
  System.out.println(byteBuffer);
  byteBuffer.putLong(1);
  System.out.println(byteBuffer);
java.nio.HeapByteBuffer[pos=0 lim=100 cap=100]
java.nio.HeapByteBuffer[pos=1 lim=100 cap=100]
java.nio.HeapByteBuffer[pos=5 lim=100 cap=100]
java.nio.HeapByteBuffer[pos=13 lim=100 cap=100]

When the read switch is through the flip method, this time limit may become the size of the writing, and pos is 0, every time data get, POST move down, the next read from this position until the excess limit when on the error.

 ByteBuffer byteBuffer =ByteBuffer.allocate(100);
 System.out.println(byteBuffer);
 byteBuffer.put("1".getBytes());
 System.out.println(byteBuffer);
 byteBuffer.putInt(1);
  System.out.println(byteBuffer);
  byteBuffer.putLong(1);
  System.out.println(byteBuffer);
  byteBuffer.flip();
  System.out.println(byteBuffer);
java.nio.HeapByteBuffer[pos=0 lim=100 cap=100]
java.nio.HeapByteBuffer[pos=1 lim=100 cap=100]
java.nio.HeapByteBuffer[pos=5 lim=100 cap=100]
java.nio.HeapByteBuffer[pos=13 lim=100 cap=100]
java.nio.HeapByteBuffer[pos=0 lim=13 cap=100]

However, these codes have a common problem faced Chinese garbled when possible, do not look above did not appear, the following examples. Just transfer a small cache, the output will be garbled. The reason is that the buffer size is 2, the data file is "abc hear the wind passed away the night def", the first reading is ab, the second reading and listening is half the c-word, so garbled. Some say the buffer zone transfer large ah, in fact, useless. Count to know, such as buffer size is 1024, a 3-byte characters, the ability to read <= 341 characters, but 3 * 341 = 1023 ah, if this case is 342 characters, be sure to read garbled. Since the remaining byte characters is not a deposit, and this is in fact directly read as FileInputStream, will be garbled, or by BufferedReader FileReader can be resolved.

try {
    FileInputStream fileInputStream = new FileInputStream(path);
    FileChannel channel = fileInputStream.getChannel();
    ByteBuffer byteBuffer = ByteBuffer.allocate(2);
    while (channel.read(byteBuffer) > 0) {
        byteBuffer.flip();
        int limit = byteBuffer.limit();
        byte[] datas = new byte[limit];
        byteBuffer.get(datas);
        System.out.println(new String(datas));
        byteBuffer.clear();
    }
} catch (IOException e) {
    e.toString();
}

Here Insert Picture Description
Online resolve this approach is even more ridiculous, few useful is garbled in extreme cases, or modify buffer size to be garbled. Come on I wrote here no matter how many characters the file, or how big the buffer, all !!!-take-all, the idea is also simple.

 private static void test4(String path) {
     try {
         FileInputStream fileOutputStream = new FileInputStream(path);
         FileChannel channel = fileOutputStream.getChannel();
         List<byte[]> data = new ArrayList<>();
         ByteBuffer byteBuffer = ByteBuffer.allocate(1);
         int totalSize = 0;
         while (channel.read(byteBuffer) > 0) {
             byteBuffer.flip();
             byte[] soure = new byte[byteBuffer.limit()];
             System.arraycopy(byteBuffer.array(), 0, soure, 0, soure.length);
             totalSize += soure.length;
             data.add(soure);
             byteBuffer.clear();
         }
         byte[] bytesData = new byte[totalSize];
         int destPos = 0;
         for (int i = 0; i < data.size(); i++) {
             System.arraycopy(data.get(i), 0, bytesData, destPos, data.get(i).length);
             destPos += data.get(i).length;
         }
         System.out.println(new String(bytesData));
     } catch (
             IOException e) {
     }
 }

Buffer

There are many types of data Buffer realize, of course, the operation of Stirng is a StringBuffer.
In the above said operating state of the Buffer, but there is a problem to explain, if the buffer size is 10, put the first five data entered, and switched to read mode, when the read number 2, to the inside the store a few numbers will complain?

The answer is three, when switching to the read mode, pos = 0, limit = 5, after two pos 2 get, put is not given immediately, but over the limit will be reported.

Other API is simple, and more trained to understand.
Here Insert Picture Description

Published 42 original articles · won praise 7 · views 7747

Guess you like

Origin blog.csdn.net/HouXinLin_CSDN/article/details/104263694