NIO review of java

Following the java IO, review about NIO! !!

What is NIO

Simply put, it's an improvement over existing IO.

Bad points of existing IO

  1. https://docs.oracle.com/javase/jp/8/docs/api/java/io/InputStream.html#read-- "This __method will be blocked __ until the input data can be read, the end of the stream is detected, or an exception is raised."

  2. Inefficient Since the processing unit is byte, char, it is not efficient. Using hige level stream (such as PrintStream) does not change the underlying processing unit.

NIO's core API

Buffer Buffer is an abstract class, and there are subclasses corresponding to basic types other than boolean.

Important elements in Buffer

Element name Description
capacity Represents the size of the Buffer
limit Buffer__The first INDEX that cannot be IO__
position Buffer__The first INDEX that can be IO__
mark The position that the position returns when you mark and reset in the Buffer

The above four factors satisfy the following 0 <= mark <= position <= limit <= capacity

Regular subclass of Buffer

  1. ByteBuffer is set / get
  2. ByteBuffer is put / get

Buffer's regular method

Method Description CharBuffer implementation
Buffer flip() Prepare the output limit = position
positon = 0
mark = -1
int capacity() Buffer capacity return return capacity
int limit() Buffer limit return return limit
int position() Buffer position returned return position
int remaining() Number of elements between position and limit return limit - position
boolean hasRemaining() Is there an element between position and limit return position < limit
Buffer position(int newPostion) set position Abbreviation
Buffer mark() Mark at the current position mark = position
return this
Buffer reset() Return position to mark int m = mark
if (m < 0)
throw new InvalidMarkException()
position = m
return this
Buffer rewind() Move position back to the top of the buffer and cancel mark position = 0
mark = -1
return this
Buffer clear() Buffer Return to initial state position = 0
limit = capacity
mark = -1
return this

CharBuffer sample

Output method


private static void showProperty(CharBuffer buffer) {
    System.out.println("capacity : " + buffer.capacity());
    System.out.println("limit : " + buffer.limit());
    System.out.println("position : " + buffer.position());
    System.out.println("toString() : " + buffer.toString());
}

Generate


CharBuffer buffer = CharBuffer.allocate(8);
System.out.println("-----After generation-----");
showProperty(buffer);

output ----- After generation ----- capacity : 8 limit : 8 position : 0 toString() :

![Buffer-allocate.png](https://qiita-image-store.s3.amazonaws.com/0/104977/2497625d-f231-645a-d64d-19076d0ed910.png)
1.The end of buffer is 8
2.IO start position(position)is 0
3. toString()Is the position~Since it is a limit, 8 nulls


#### **`put()`**
```java

buffer.put('a');
buffer.put('b');
buffer.put('c');
 System.out.println ("----- After put -----");
showProperty(buffer);
 ----- After put -----
capacity : 8
limit : 8
position : 3
toString() :      

Buffer-put.png

  1. put()I did it three times, so the posiont+3
  2. toString()Is the position~Since it is a limit, 5 nulls

flip()


buffer.flip();
 System.out.println ("----- after flip -----");
showProperty(buffer);
 ----- After flip -----
capacity : 8
limit : 3
position : 0
toString() : abc

Buffer-flip.png 1.First INDEX that cannot be IO(limit)Is 3 2.The first INDEX that can be IO(position)Start position is 0 3. toString()Is the position~Because it is a limitabc

get()


buffer.get();
buffer.get();
System.out.println("-----get-----");
showProperty(buffer);
 ----- After get -----
capacity : 8
limit : 3
position : 2
toString() : c

Buffer-get.png

  1. get()Since it is twice, the position is+2、cPoint to
    1. toString()Is the position~Because it is a limitc

clear()


buffer.clear();
 System.out.println ("----- after clear -----");
showProperty(buffer);
System.out.println("get(2) : " + buffer.get(2));
 ----- After clear -----
capacity : 8
limit : 8
position : 0
toString() : abc     
get(2) : c

Buffer-clear.png 1.Since it returns to the initial position, position=0, limit,capacity=8 2.Not shown here, but mark=-1 3. clear()Just return the position__Because it does not clear the buffer__、 clear()Get even after(2)socが取得soきる

###bonus ByterBuffer has allocateDirect()There is a method to get an instance with. The IO efficiency is high, but the production cost is high, so it is not suitable for disposable use.

Channel

Direct contact(HDD, net, etc.)It is a pipe that connects to, and all IO__Through Buffer__To do.

IO method Description
Channel#map Put the range of start and end positions in Buffer
Read position(Channel.position)Do not record
Channel#read Put in Buffer from Channel
Record the read position
Channel#write Put in Channel from Buffer
Record the writing position

channel-img.png

###Partial implementation of Channel

FileChannel

map(), write()

channel-in.txt(UTF-8)


 ab12
 Ai

ab12 = 4byte Ai= 9byte \r\n = 2byte

map(),write()


try (
    FileChannel channelIn = new FileInputStream(f).getChannel();
    FileChannel channelOut = new FileOutputStream("./NIO/channel-out.txt").getChannel()) {

    // map()
    MappedByteBuffer mappedByteBuffer = channelIn.map(
        FileChannel.MapMode.READ_ONLY, 0, f.length()
    );
    System.out.println("----channel#map----");
    System.out.println("buffer capacity : " + mappedByteBuffer.capacity());
    System.out.println("buffer limit : " + mappedByteBuffer.limit());
    System.out.println("buffer position : " + mappedByteBuffer.position());
    System.out.println("channel position : " + channelIn.position());

    // write
    channelOut.write(mappedByteBuffer);
    System.out.println("----channel#write----");
    System.out.println("buffer capacity : " + mappedByteBuffer.capacity());
    System.out.println("buffer limit : " + mappedByteBuffer.limit());
    System.out.println("buffer position : " + mappedByteBuffer.position());
    System.out.println("channel position : " + channelOut.position());
} catch (IOException ex) {
    System.out.println(ex.getMessage());
}
----channel#map----
buffer capacity : 15
buffer limit : 15
buffer position : 0
channel position : 0
----channel#write----
buffer capacity : 15
buffer limit : 15
buffer position : 15
channel position : 15

*map processing * getChannel() ->FileChannel instantiation * 0, f.length() -> 0~Get 15 bytes * buffer position : 0 -> flip()Done * channel position -?Do not keep the read position in the file

read()

File f = new File("./NIO/channel-in.txt");
try (
    FileChannel inChannel = new FileInputStream(f).getChannel()) {
    
    ByteBuffer byteBuffer = ByteBuffer.allocate(8);
    int hasRead = 0;

 System.out.println ("---- channel # read 1st ----");
    hasRead = inChannel.read(byteBuffer);
    System.out.println("buffer capacity : " + byteBuffer.capacity());
    System.out.println("buffer limit : " + byteBuffer.limit());
    System.out.println("buffer position : " + byteBuffer.position());
    System.out.println("channel position : " + inChannel.position());
    System.out.println("hasRead : " + hasRead);

    byteBuffer.clear();

 System.out.println ("---- channel # read 2nd ----");
    hasRead = inChannel.read(byteBuffer);
    System.out.println("buffer capacity : " + byteBuffer.capacity());
    System.out.println("buffer limit : " + byteBuffer.limit());
    System.out.println("buffer position : " + byteBuffer.position());
    System.out.println("channel position : " + inChannel.position());
    System.out.println("hasRead : " + hasRead);
} catch (IOException ex) {
    System.out.println(ex.getMessage());
}
 ---- channel # read 1st time ----
buffer capacity : 8
buffer limit : 8
buffer position : 8
channel position : 8
hasRead : 8
 ---- channel # read 2nd time ----
buffer capacity : 8
buffer limit : 8
buffer position : 7
channel position : 15
hasRead : 7

*read 1st time * buffer position : 8 ->8 bytes read * channel position : 8 ->Next is file index= 8(9th byte)Read from *read 2nd time * buffer position : 7 ->7 bytes read * channel position : 15 ->Next is file index= 15(9th byte)Read from

Charset

Java uses Unicode by default, but garbled characters may occur when reading other character codes. Charset is provided to convert between byte and char.

IO method Description
CharBuffer Charset#decode(ByteBuffer buf) ByteBuffer to CharBuffer
ByteBuffer Charset#encode(CharBuffer buf) CharBuffer to ByteBuffer
ByteBuffer Charset#encode(String str) String to ByteBuffer

###Get charset supported by java

Charset.availableCharsets()


 // Charset list
Charset.availableCharsets().entrySet().forEach(System.out::println);

// defalut
System.out.println("default charset : " + Charset.defaultCharset()); // UTF-8

part


 ・ ・ ・ Abbreviation
Shift_JIS=Shift_JIS
UTF-16=UTF-16
UTF-32=UTF-32
UTF-8=UTF-8
 ・ ・ ・ Abbreviation

ByteBuffer to CharBuffer

Read SJIS file


File f = new File("./NIO/file-sjis-in.txt");
try (
    FileChannel inChannel = new FileInputStream(f).getChannel()) {

    // FileChannel to ByteBuffer
    ByteBuffer byteBuffer = ByteBuffer.allocate(6);
    inChannel.read(byteBuffer);
    byteBuffer.flip();

    // Shift_JIS
    Charset sjis = Charset.forName("Shift_JIS");

    // decode buff with SJIS
    CharBuffer charBuffer = sjis.decode(byteBuffer);
    System.out.println("str : " + charBuffer.toString());
} catch (IOException ex) {
    System.out.println(ex.getMessage());
}

String to ByteBuffer

String(unicode)Is written in SJIS


try (
    FileChannel outChannel = new FileOutputStream("./NIO/file-sjis-out.txt").getChannel()) {

    // unicode
 String str = "123 Ai" + System.lineSeparator () + "SHIFT-JIS";
    // Shift_JIS
    Charset sjis = Charset.forName("Shift_JIS");
    // encode buff with SJIS
    ByteBuffer byteBuffer = sjis.encode(str);
    // write to file
    outChannel.write(byteBuffer);
} catch (IOException ex) {
    System.out.println(ex.getMessage());
}

Or

It's also in String! !!


new String(byte[] xx, "Shift_JIS");

###One unclear point utf-8(1byte ~ 6byte)When the number of bytes differs depending on the character, such as What should I do with the Buffer size? ?? ??

UTF-8 files


 ab ai

ab = 2byte Ai= 3byte + 3byte

ByteBuffer byteBuffer = ByteBuffer.allocate(6)If set to ab ah + 1st byteGoes into the buffer and decodesab ah�become.

What should I do in this case? ?? ??

  1. ~~Use the common multiple of the character set.~~ ~~「1,2,3,4,5,Since it is "6", use a multiple of 60 bytes as the Buffer size.~~

2.Determine the garbled characters, put them at the beginning of the Buffer, adjust the position, and read. ⇒ map()Does not keep block reading & file position! ~~Do I have to specify a size that does not garble? ??~~

The solution is below.

control Description
onMalformedInput Illegal input error
onUnmappableCharacter Unmapped character error
Type Description
CodingErrorAction.IGNORE Ignore error characters
CodingErrorAction.REPLACE Error character replacement
CodingErrorAction.REPORT Error report

CodingErrorAction.IGNORE

IGNORE sample


File f = new File("./a/file-utf8-in.txt");
try (
    FileChannel inChannel = new FileInputStream(f).getChannel()) {
    ByteBuffer byteBuffer = ByteBuffer.allocate(6);
    while (inChannel.read(byteBuffer) > -1) {
 // IO preparation
        byteBuffer.flip();

        Charset utf8 = Charset.forName("UTF-8");
        CharsetDecoder decoder = utf8.newDecoder();

        CharBuffer charBuffer2 = decoder
            .onMalformedInput(CodingErrorAction.IGNORE)
            .decode(byteBuffer);
        System.out.print(charBuffer2.toString());
        byteBuffer.clear();
    }
} catch (IOException ex) {
    System.out.println(ex.getMessage());
}

output


 ab ah

IWas ignored

CodingErrorAction.IGNORE

IGNORE


File f = new File("./a/file-utf8-in.txt");
try (
    FileChannel inChannel = new FileInputStream(f).getChannel()) {
    ByteBuffer byteBuffer = ByteBuffer.allocate(6);
    while (inChannel.read(byteBuffer) > -1) {
 // IO preparation
        byteBuffer.flip();
        Charset utf8 = Charset.forName("UTF-8");
        CharsetDecoder decoder = utf8.newDecoder();
        CharBuffer charBuffer2 = decoder
 .onMalformedInput (CodingErrorAction.REPLACE) .replaceWith ("O")
            .decode(byteBuffer);
        System.out.print(charBuffer2.toString());
        byteBuffer.clear();
    }
} catch (IOException ex) {
    System.out.println(ex.getMessage());
}

output


 ab Aoo

I1st byte ⇒ I2nd byte ⇒ I3rd byte ⇒

CodingErrorAction.REPORT

IGNORE,REPLACE destroys the original data !!

REPORT


File f = new File("./a/file-utf8-in.txt");
try (
    FileChannel inChannel = new FileInputStream(f).getChannel()) {
    ByteBuffer byteBuffer = ByteBuffer.allocate(6);
    while (inChannel.read(byteBuffer) > -1) {
        byteBuffer.flip();
        Charset utf8 = Charset.forName("UTF-8");
        CharsetDecoder decoder = utf8.newDecoder();
        try {
            CharBuffer charBuffer = decoder
                .onMalformedInput(CodingErrorAction.REPORT)
                .decode(byteBuffer);

 // Output
            System.out.print(charBuffer.toString());
            byteBuffer.clear();
        } catch (MalformedInputException ex) {
 // Error occurrence position and end position
            int errorIndexStart = byteBuffer.position();
            int errorIndexEnd = byteBuffer.limit();

 // Output to normal position
            byteBuffer.flip();
            CharBuffer charBuffer = decoder
                .decode(byteBuffer);
            System.out.print(charBuffer.toString());

 // Move error position start-end to buffer top
            byteBuffer.clear();
            for (int i = errorIndexStart; i < errorIndexEnd; i++) {
                byteBuffer.put(byteBuffer.get(i));
            }
        }
    }
} catch (IOException ex) {
    System.out.println(ex.getMessage());
}
 ab ai

1.When an error occurs, first output to the normal position. 2.Move from the error occurrence position to the end of the buffer 3.The next read is from after the error length, not from 0 4. utf-8 is 1 to 6 bytes, so allocate at least(6)Do you need?

Is this really the best? ??

FileLock

Represents a lock on a file

FileChannel lock method Description
FileChannel#lock() lock(0L, Long.MAX_VALUE, false)
FileChannel#lock(long position, long size, boolean shared) Lock range, shared lock, exclusive lock can be specified
FileChannel#tryLock() tryLock(0L, Long.MAX_VALUE, false)
FileChannel#tryLock(long position, long size, boolean shared) Lock range, shared lock, exclusive lock can be specified

lock()And tryLock()The difference of

lock()Blocks threads until the lock is acquired. tryLock returns null if the lock cannot be acquired.

lock()

lock sample


try (FileChannel fileChannel = new FileOutputStream("file-lock-out.txt").getChannel();) {
    FileLock lock = fileChannel.lock();
 System.out.println ("lock was obtained");
 System.out.println ("Keep lock for 60 seconds");
    Thread.sleep(60 * 1000);
    lock.release();
} catch (IOException | InterruptedException ex) {
    System.out.println("1" + ex.getMessage());
}

When the above is executed twice with different jvm

output of jvm1


 I was able to get the lock
 Keep lock for 60 seconds

There is no output because the output of jvm2 waits.

tryLock()

tryLock()sample


try (FileChannel fileChannel = new FileOutputStream("file-lock-out.txt").getChannel();) {
    FileLock lock = fileChannel.tryLock();
    if (lock != null) {
 System.out.println ("tryLock acquired");
        Thread.sleep(60 * 1000);
        lock.release();
    } else {
        System.out.println("lock is null");
    }
} catch (IOException | InterruptedException ex) {
    System.out.println(ex.getMessage());
}

jvm1 output


 I was able to get tryLock

jvm2 output


lock is null

###Other 1.Since the lock is owned by the jvm, the same file cannot be locked with the same jvm. 2.On some platforms, the lock is released when the FileChannel is closed. So it's not good to open multiple File Channels for locked files. 3.On some platforms, file locking is recommended, not compulsory. ⇒ You can read and write without locking.

#Next is NIO.2 https://qiita.com/liguofeng29/items/3d0ba350a1547630727b

Recommended Posts

NIO.2 review of java
NIO review of java
Review of java Shilber
Java NIO 2 review notes
Java review
Java IO review
[Java] Overview of Java
Expired collection of java
Predicted Features of Java
[Java] Significance of serialVersionUID
java --Unification of comments
Java inner class review
java (merits of polymorphism)
A quick review of Java learned in class
Review Java annotations now
Review java8 ~ Lambda expression ~
[Java] Three features of Java
Summary of Java support 2018
Java review ③ (Basic usage of arrays / reference type)
A quick review of Java learned in class part4
[Java] About Objects.equals () and Review of String comparisons (== and equals)
A quick review of Java learned in class part3
A quick review of Java learned in class part2
About an instance of java
[Java] Mirage-Basic usage of SQL
[Java] Beginner's understanding of Servlet-②
[Java] Practice of exception handling [Exception]
[Java11] Stream Summary -Advantages of Stream-
Progate Java (Beginner) Review & Summary
[Java] Creation of original annotation
[Java] Beginner's understanding of Servlet-①
Java end of month plusMonths
[Java] Summary of regular expressions
[Java] Summary of operators (operator)
[Java] Implementation of Faistel Network
[Java] Comparator of Collection class
Summary of Java language basics
Summary of Java Math class
Enumeration of all combinations Java
java (inheritance of is-a principle)
Implementation of gzip in java
Advantages and disadvantages of Java
Benefits of Java static method
[Java] Summary of control syntax
Implementation of tri-tree in Java
Summary of java error processing
[Java] Summary of design patterns
[Java] Summary of mathematical operations
Review of Ruby basic grammar
Think of a Java update strategy
[Java] Delete the elements of List
[For beginners] Summary of java constructor
Various methods of Java String class
Root cause of java framework bugs
About fastqc of Biocontainers and Java
[Java version] The story of serialization
Summary of [Java silver study] package
About Lambda, Stream, LocalDate of Java8
Extraction of "ruby" double hash * Review
Story of passing Java Gold SE8
Sort a List of Java objects