Following the java IO, review about NIO! !!
Simply put, it's an improvement over existing IO.
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."
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.
Buffer Buffer is an abstract class, and there are subclasses corresponding to basic types other than boolean.
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
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 |
return toString (position (), limit ());
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() :
flip()
buffer.flip();
System.out.println ("----- after flip -----");
showProperty(buffer);
----- After flip -----
capacity : 8
limit : 3
position : 0
toString() : abc
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
c
Point toc
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
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.
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 |
###Partial implementation of Channel
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
out.write
-> position ~Write limitbuffer position : 15
->The position was moved by the amount written outchannel position : 15
->Next time file index= 15(16th byte)Write fromFile 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
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
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(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 byte
Goes into the buffer and decodesab ah�
become.
What should I do in this case? ?? ??
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 |
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
I
Was ignored
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
I
1st byte ⇒
I
2nd byte ⇒
I
3rd byte ⇒
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? ??
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()Blocks threads until the lock is acquired. tryLock returns null if the lock cannot be acquired.
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()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