Lesen Sie nach dem Java IO einen Bericht über NIO! !!
Einfach ausgedrückt ist dies eine Verbesserung gegenüber vorhandenen E / A.
https://docs.oracle.com/javase/jp/8/docs/api/java/io/InputStream.html#read-- "Diese Methode wird blockiert, bis die Eingabedaten gelesen werden können, das Ende des Streams erkannt wird oder eine Ausnahme ausgelöst wird."
Ineffizient Da die Verarbeitungseinheit Byte, char ist, ist sie nicht effizient. Selbst wenn Sie einen Stream auf hoher Ebene verwenden (z. B. PrintStream), ändert sich die Basisverarbeitungseinheit nicht.
Buffer Buffer ist eine abstrakte Klasse, und es gibt Unterklassen, die anderen Grundtypen als Boolean entsprechen.
Elementname | Erläuterung |
---|---|
capacity | Repräsentiert die Größe des Puffers |
limit | Puffer__Der erste INDEX, der nicht IO sein kann__ |
position | Puffer__Der erste INDEX, der IO sein kann__ |
mark | Die Position, die die Position zurückgibt, wenn Sie im Puffer markieren und zurücksetzen |
Die obigen vier Faktoren erfüllen die folgenden Anforderungen 0 <= mark <= position <= limit <= capacity
Methode | Erläuterung | Implementierung von CharBuffer |
---|---|---|
Buffer flip() | Bereiten Sie die Ausgabe vor | limit = position positon = 0 mark = -1 |
int capacity() | Rückgabe der Pufferkapazität | return capacity |
int limit() | Rückgabe des Pufferlimits | return limit |
int position() | Pufferposition zurückgegeben | return position |
int remaining() | Anzahl der Elemente zwischen Position und Grenze | return limit - position |
boolean hasRemaining() | Gibt es ein Element zwischen Position und Grenze? | return position < limit |
Buffer position(int newPostion) | Position setzen | Abkürzung |
Buffer mark() | An der aktuellen Position markieren | mark = position return this |
Buffer reset() | Position zur Markierung zurückbringen | int m = mark if (m < 0) throw new InvalidMarkException() position = m return this |
Buffer rewind() | Bewegen Sie die Position zurück zum oberen Rand des Puffers und brechen Sie die Markierung ab | position = 0 mark = -1 return this |
Buffer clear() | Puffer Zurück zum Ausgangszustand | position = 0 limit = capacity mark = -1 return this |
return toString (position (), limit ());
Ausgabemethode
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());
}
Generieren
CharBuffer buffer = CharBuffer.allocate(8);
System.out.println("-----Nach der Generation-----");
showProperty(buffer);
Ausgabe
----- Nach der 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.Das Ende des Puffers ist 8
2.IO Startposition(position)ist 0
3. toString()Ist die Position~Da es sich um ein Limit handelt, 8 Nullen
#### **`put()`**
```java
buffer.put('a');
buffer.put('b');
buffer.put('c');
System.out.println ("----- After put -----");
showProperty(buffer);
----- Nach dem Put -----
capacity : 8
limit : 8
position : 3
toString() :
flip()
buffer.flip();
System.out.println ("----- nach dem Umdrehen -----");
showProperty(buffer);
----- Nach dem Umdrehen -----
capacity : 8
limit : 3
position : 0
toString() : abc
1.Erster INDEX, der nicht IO sein kann(limit)Ist 3
2.Der erste INDEX, der IO sein kann(position)Startposition ist 0
3. toString()Ist die Position~Weil es eine Grenze istabc
get()
buffer.get();
buffer.get();
System.out.println("-----get-----");
showProperty(buffer);
----- Nach get -----
capacity : 8
limit : 3
position : 2
toString() : c
c
Zeigen aufc
clear()
buffer.clear();
System.out.println ("----- nach Löschen -----");
showProperty(buffer);
System.out.println("get(2) : " + buffer.get(2));
----- Nach dem Löschen -----
capacity : 8
limit : 8
position : 0
toString() : abc
get(2) : c
1.Da es zur Ausgangsposition zurückkehrt, Position=0, limit,capacity=8
2.Hier nicht gezeigt, aber markieren=-1
3. clear()Geben Sie einfach die Position zurück__Weil es den Puffer nicht löscht__、
clear()Holen Sie sich auch nach(2)damitc
が取得damitきる
###Bonus ByterBuffer hat allocateDirect()Es gibt eine Methode, mit der eine Instanz abgerufen werden kann. Die E / A-Effizienz ist hoch, aber die Produktionskosten sind hoch, sodass sie nicht für den Einweggebrauch geeignet sind.
Direkten Kontakt(Festplatte, Netz usw.)Es ist eine Pipe, die mit und allen E / A verbunden ist__Durch Puffer__Machen.
IO-Methode | Erläuterung |
---|---|
Channel#map | Stellen Sie den Bereich der Start- und Endpositionen in Buffer Position lesen(Channel.position)Nicht aufnehmen |
Channel#read | Puffer vom Kanal einfügen Notieren Sie die Leseposition |
Channel#write | Kanal aus Puffer einfügen Notieren Sie die Schreibposition |
###Teilweise Implementierung von 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
*Kartenverarbeitung
* getChannel()
->FileChannel-Instanziierung
* 0, f.length()
-> 0~Holen Sie sich 15 Bytes
* buffer position : 0
-> flip()Erledigt
* channel position
-?Halten Sie die Leseposition nicht in der Datei
out.write
-> position ~Schreiblimitbuffer position : 15
->Die Position wurde um den ausgeschriebenen Betrag verschobenchannel position : 15
->Nächstes Mal Dateiindex= 15(16. Byte)Schreiben Sie vonFile 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 ("---- Kanal # 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 ("---- Kanal # 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());
}
---- Kanal # 1. Mal gelesen ----
buffer capacity : 8
buffer limit : 8
buffer position : 8
channel position : 8
hasRead : 8
---- Kanal # 2. Mal gelesen ----
buffer capacity : 8
buffer limit : 8
buffer position : 7
channel position : 15
hasRead : 7
*1. Mal lesen
* buffer position : 8
->8 Bytes gelesen
* channel position : 8
->Als nächstes folgt der Dateiindex= 8(9. Byte)Lesen Sie aus
*2. Mal lesen
* buffer position : 7
->7 Bytes gelesen
* channel position : 15
->Als nächstes folgt der Dateiindex= 15(9. Byte)Lesen Sie aus
Java verwendet standardmäßig Unicode, aber beim Lesen anderer Zeichencodes können verstümmelte Zeichen auftreten. Der Zeichensatz dient zum Konvertieren von Byte und Zeichen.
IO-Methode | Erläuterung |
---|---|
CharBuffer Charset#decode(ByteBuffer buf) | ByteBuffer to CharBuffer |
ByteBuffer Charset#encode(CharBuffer buf) | CharBuffer to ByteBuffer |
ByteBuffer Charset#encode(String str) | String to ByteBuffer |
###Zeichensatz wird von Java unterstützt
Charset.availableCharsets()
// Zeichensatzliste
Charset.availableCharsets().entrySet().forEach(System.out::println);
// defalut
System.out.println("default charset : " + Charset.defaultCharset()); // UTF-8
Teil
・ ・ ・ Abkürzung
Shift_JIS=Shift_JIS
UTF-16=UTF-16
UTF-32=UTF-32
UTF-8=UTF-8
・ ・ ・ Abkürzung
SJIS-Datei lesen
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)Ist in SJIS geschrieben
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());
}
Oder
Es ist auch in String! !!
new String(byte[] xx, "Shift_JIS");
###Ein unklarer Punkt utf-8(1byte ~ 6byte)Wenn die Anzahl der Bytes je nach Zeichen unterschiedlich ist, z Was soll ich mit der Puffergröße machen? ?? ??
UTF-8 Dateien
ab ai
ab = 2byte Ai= 3byte + 3byte
ByteBuffer byteBuffer = ByteBuffer.allocate(6)
Wenn eingestellt auf
ab ah
+ 1. Byte
Geht in den Puffer und dekodiertab ah�
werden.
Was soll ich in diesem Fall tun? ?? ??
2.Bestimmen Sie verstümmelte Zeichen, setzen Sie sie an den Anfang von Buffer, passen Sie die Position an und lesen Sie. ⇒ map()Blocklesen & Dateiposition nicht beibehalten! ~~Muss ich eine Größe angeben, die nicht verstümmelt? ??~~
Die Lösung ist unten.
Steuerung | Erläuterung |
---|---|
onMalformedInput | Unzulässiger Eingabefehler |
onUnmappableCharacter | Nicht zugeordneter Zeichenfehler |
Art | Erläuterung |
---|---|
CodingErrorAction.IGNORE | Fehlerzeichen ignorieren |
CodingErrorAction.REPLACE | Fehler beim Ersetzen von Zeichen |
CodingErrorAction.REPORT | Fehlermeldung |
IGNORE Probe
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-Vorbereitung
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());
}
Ausgabe
ab ah
ich
Wurde ignoriert
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-Vorbereitung
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());
}
Ausgabe
ab Aoo
ich
1. Byte ⇒
ich
2. Byte ⇒
ich
3. Byte ⇒
IGNORE,REPLACE zerstört die Originaldaten !!
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);
// Ausgabe
System.out.print(charBuffer.toString());
byteBuffer.clear();
} catch (MalformedInputException ex) {
// Fehlerauftrittsposition und Endposition
int errorIndexStart = byteBuffer.position();
int errorIndexEnd = byteBuffer.limit();
// Ausgabe in normale Position
byteBuffer.flip();
CharBuffer charBuffer = decoder
.decode(byteBuffer);
System.out.print(charBuffer.toString());
// Verschiebe den Anfang bis zum Ende der Fehlerposition an den Anfang des Puffers
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.Wenn ein Fehler auftritt, wird zuerst an die normale Position ausgegeben. 2.Bewegen Sie sich von der Position des Auftretens des Fehlers zum Ende des Puffers 3.Der nächste Lesevorgang erfolgt nach der Fehlerlänge, nicht ab 0 4. utf-8 ist 1 bis 6 Bytes, also ordnen Sie mindestens zu(6)Brauchst du?
Ist das wirklich das Beste? ??
Stellt eine Sperre für eine Datei dar
FileChannel-Sperrmethode | Erläuterung |
---|---|
FileChannel#lock() | lock(0L, Long.MAX_VALUE, false) |
FileChannel#lock(long position, long size, boolean shared) | Sperrbereich, gemeinsame Sperre, exklusive Sperre können angegeben werden |
FileChannel#tryLock() | tryLock(0L, Long.MAX_VALUE, false) |
FileChannel#tryLock(long position, long size, boolean shared) | Sperrbereich, gemeinsame Sperre, exklusive Sperre können angegeben werden |
lock()Blockiert Threads bis zur Sperrenerfassung. tryLock gibt null zurück, wenn die Sperre nicht erreicht werden kann.
Probe sperren
try (FileChannel fileChannel = new FileOutputStream("file-lock-out.txt").getChannel();) {
FileLock lock = fileChannel.lock();
System.out.println ("Sperre wurde erhalten");
System.out.println ("Sperre 60 Sekunden lang halten");
Thread.sleep(60 * 1000);
lock.release();
} catch (IOException | InterruptedException ex) {
System.out.println("1" + ex.getMessage());
}
Wenn das oben genannte zweimal mit verschiedenen jvm ausgeführt wird
Ausgabe von jvm1
Ich konnte das Schloss bekommen
Halten Sie die Sperre für 60 Sekunden
Es erfolgt keine Ausgabe, da die Ausgabe von jvm2 wartet.
tryLock()Stichprobe
try (FileChannel fileChannel = new FileOutputStream("file-lock-out.txt").getChannel();) {
FileLock lock = fileChannel.tryLock();
if (lock != null) {
System.out.println ("tryLock wurde erworben");
Thread.sleep(60 * 1000);
lock.release();
} else {
System.out.println("lock is null");
}
} catch (IOException | InterruptedException ex) {
System.out.println(ex.getMessage());
}
jvm1 Ausgabe
Ich konnte tryLock bekommen
jvm2 Ausgabe
lock is null
###Andere 1.Da die Sperre jvm gehört, können Sie nicht dieselbe Datei mit derselben jvm sperren. 2.Auf einigen Plattformen wird die Sperre aufgehoben, wenn der FileChannel geschlossen wird. Es ist also nicht gut, mehrere FileChannels für gesperrte Dateien zu öffnen. 3.Auf einigen Plattformen werden Dateisperren empfohlen und sind nicht obligatorisch. ⇒ Sie können ohne Sperre lesen und schreiben.
#Als nächstes kommt NIO.2 https://qiita.com/liguofeng29/items/3d0ba350a1547630727b
Recommended Posts