Examen NIO de Java

Après le java IO, revue de NIO! !!

Qu'est-ce que NIO

En termes simples, il s'agit d'une amélioration par rapport aux E / S existantes.

Mauvais points d'E / S existantes

  1. https://docs.oracle.com/javase/jp/8/docs/api/java/io/InputStream.html#read-- "Cette method est bloquée jusqu'à ce que les données d'entrée puissent être lues, que la fin du flux soit détectée ou qu'une exception soit déclenchée."

  2. Inefficace Puisque l'unité de traitement est byte, char, elle n'est pas efficace. Même si vous utilisez un flux de niveau élevé (tel que PrintStream), l'unité de traitement de base ne change pas.

API principale de NIO

Buffer Buffer est une classe abstraite, et il existe des sous-classes correspondant à des types de base autres que booléens.

Éléments importants dans Buffer

Nom de l'élément La description
capacity Représente la taille du tampon
limit Tampon__Le premier INDEX qui ne peut pas être IO__
position Tampon__Le premier INDEX qui peut être IO__
mark La position que la position renvoie lorsque vous marquez et réinitialisez dans le tampon

Les quatre facteurs ci-dessus satisfont ce qui suit 0 <= mark <= position <= limit <= capacity

Sous-classe régulière de Buffer

  1. ByteBuffer est défini / obtenu
  2. ByteBuffer est mis / get

Méthode régulière de Buffer

Méthode La description Implémentation de CharBuffer
Buffer flip() Préparez la sortie limit = position
positon = 0
mark = -1
int capacity() Retour de capacité tampon return capacity
int limit() Retour de limite de tampon return limit
int position() Position du tampon retournée return position
int remaining() Nombre d'éléments entre la position et la limite return limit - position
boolean hasRemaining() Y a-t-il un élément entre la position et la limite return position < limit
Buffer position(int newPostion) définir la position Abréviation
Buffer mark() Marquer à la position actuelle mark = position
return this
Buffer reset() Position de retour pour marquer int m = mark
if (m < 0)
throw new InvalidMarkException()
position = m
return this
Buffer rewind() Remettre la position en haut du tampon et annuler la marque position = 0
mark = -1
return this
Buffer clear() Buffer Retour à l'état initial position = 0
limit = capacity
mark = -1
return this

Échantillon CharBuffer

Méthode de sortie


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());
}

produire


CharBuffer buffer = CharBuffer.allocate(8);
System.out.println("-----Après génération-----");
showProperty(buffer);

production ----- Après la génération ----- 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.La fin du tampon est 8
2.Position de départ IO(position)vaut 0
3. toString()Est la position~Puisqu'il s'agit d'une limite, 8 nuls


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

buffer.put('a');
buffer.put('b');
buffer.put('c');
 System.out.println ("----- Après avoir mis -----");
showProperty(buffer);
 ----- Après avoir mis -----
capacity : 8
limit : 8
position : 3
toString() :      

Buffer-put.png

  1. put()Je l'ai fait trois fois, donc le posiont+3
  2. toString()Est la position~Puisqu'il s'agit d'une limite, 5 nuls

flip()


buffer.flip();
 System.out.println ("----- après le retournement -----");
showProperty(buffer);
 ----- Après retournement -----
capacity : 8
limit : 3
position : 0
toString() : abc

Buffer-flip.png 1.Premier INDEX qui ne peut pas être IO(limit)Est 3 2.Le premier INDEX qui peut être IO(position)La position de départ est 0 3. toString()Est la position~Parce que c'est une limiteabc

get()


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

Buffer-get.png

  1. get()Puisqu'il est deux fois, la position est+2、cPointer vers
    1. toString()Est la position~Parce que c'est une limitec

clear()


buffer.clear();
 System.out.println ("----- après effacement -----");
showProperty(buffer);
System.out.println("get(2) : " + buffer.get(2));
 ----- Après effacement -----
capacity : 8
limit : 8
position : 0
toString() : abc     
get(2) : c

Buffer-clear.png 1.Puisqu'il revient à la position initiale, la position=0, limit,capacity=8 2.Non montré ici, mais marquez=-1 3. clear()Il suffit de retourner la position__Parce qu'il ne vide pas le tampon__、 clear()Obtenez même après(2)alorscが取得alorsきる

###prime ByterBuffer a allocateDirect()Il existe une méthode pour obtenir une instance avec. L'efficacité IO est élevée, mais le coût de production est élevé, il n'est donc pas adapté à une utilisation jetable.

Channel

Contact direct(Disque dur, réseau, etc.)C'est un tuyau qui se connecte à, et tous les IO__Grâce au tampon__Faire.

Méthode IO La description
Channel#map Mettez la plage de positions de début et de fin dans Buffer
Lire la position(Channel.position)Ne pas enregistrer
Channel#read Mettre dans le tampon à partir du canal
Enregistrer la position de lecture
Channel#write Mettre dans le canal à partir du tampon
Enregistrez la position d'écriture

channel-img.png

###Implémentation partielle de 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

*traitement de la carte * getChannel() ->Instanciation FileChannel * 0, f.length() -> 0~Obtenez 15 octets * buffer position : 0 -> flip()Terminé * channel position -?Ne pas maintenir la position de lecture dans le fichier

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());
}
 ---- numéro de canal lu 1ère fois ----
buffer capacity : 8
buffer limit : 8
buffer position : 8
channel position : 8
hasRead : 8
 ---- numéro de canal lu 2ème fois ----
buffer capacity : 8
buffer limit : 8
buffer position : 7
channel position : 15
hasRead : 7

*lire 1ère fois * buffer position : 8 ->8 octets lus * channel position : 8 ->Vient ensuite l'index des fichiers= 8(9e octet)Lire de *lire la 2ème fois * buffer position : 7 ->7 octets lus * channel position : 15 ->Vient ensuite l'index des fichiers= 15(9e octet)Lire de

Charset

java utilise Unicode par défaut, mais des caractères déformés peuvent se produire lors de la lecture d'autres codes de caractères. Charset est fourni pour la conversion d'octet et de caractère.

Méthode IO La 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

###Obtenir le jeu de caractères pris en charge par java

Charset.availableCharsets()


 // Liste des jeux de caractères
Charset.availableCharsets().entrySet().forEach(System.out::println);

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

partie


 ・ ・ ・ Abréviation
Shift_JIS=Shift_JIS
UTF-16=UTF-16
UTF-32=UTF-32
UTF-8=UTF-8
 ・ ・ ・ Abréviation

ByteBuffer to CharBuffer

Lire le fichier SJIS


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)Est écrit en SJIS


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

    // unicode
 Chaîne 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());
}

Ou

C'est aussi dans String! !!


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

###Un point peu clair utf-8(1byte ~ 6byte)Lorsque le nombre d'octets diffère selon le caractère, tel que Que dois-je faire avec la taille du tampon? ?? ??

UTF-8 fiches


 ab ai

ab = 2byte Ai= 3byte + 3byte

ByteBuffer byteBuffer = ByteBuffer.allocate(6)Si défini sur ab ah + 1er octetVa dans le tampon et décodeab ah�devenir.

Que dois-je faire dans ce cas? ?? ??

  1. ~~Utilisez le multiple commun du jeu de caractères.~~ ~~「1,2,3,4,5,Puisqu'il est "6", utilisez un multiple de 60 octets comme taille du tampon.~~

2.Déterminez les caractères déformés, placez-les au début du tampon, ajustez la position et lisez. ⇒ map()Ne bloque pas la lecture et la position du fichier! ~~Dois-je spécifier une taille qui ne déforme pas? ??~~

La solution est ci-dessous.

contrôle La description
onMalformedInput Erreur de saisie illégale
onUnmappableCharacter Erreur de caractère non mappé
Type La description
CodingErrorAction.IGNORE Ignorer les caractères d'erreur
CodingErrorAction.REPLACE Remplacement du caractère d'erreur
CodingErrorAction.REPORT Rapport d'erreur

CodingErrorAction.IGNORE

Échantillon IGNORER


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) {
 // Préparation IO
        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());
}

production


 ab ah

jeA été ignoré

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) {
 // Préparation IO
        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());
}

production


 ab Aoo

je1er octet ⇒ je2e octet ⇒ je3e octet ⇒

CodingErrorAction.REPORT

IGNORE,REPLACE détruit les données d'origine !!

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);

 // Production
            System.out.print(charBuffer.toString());
            byteBuffer.clear();
        } catch (MalformedInputException ex) {
 // Position d'occurrence d'erreur et position finale
            int errorIndexStart = byteBuffer.position();
            int errorIndexEnd = byteBuffer.limit();

 // Sortie en position normale
            byteBuffer.flip();
            CharBuffer charBuffer = decoder
                .decode(byteBuffer);
            System.out.print(charBuffer.toString());

 // Déplace le début à la fin de la position d'erreur au début du tampon
            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.Lorsqu'une erreur se produit, première sortie en position normale. 2.Passer de la position d'occurrence d'erreur à la fin du tampon 3.La lecture suivante est après la longueur de l'erreur, pas à partir de 0 4. utf-8 est de 1 à 6 octets, donc allouez au moins(6)As-tu besoin?

Est-ce vraiment le meilleur? ??

FileLock

Représente un verrou sur un fichier

Méthode de verrouillage FileChannel La description
FileChannel#lock() lock(0L, Long.MAX_VALUE, false)
FileChannel#lock(long position, long size, boolean shared) Plage de verrouillage, verrouillage partagé, verrouillage exclusif peut être spécifié
FileChannel#tryLock() tryLock(0L, Long.MAX_VALUE, false)
FileChannel#tryLock(long position, long size, boolean shared) Plage de verrouillage, verrouillage partagé, verrouillage exclusif peut être spécifié

lock()Et essayez de verrouiller()La différence de

lock()Bloque les filetages jusqu'à l'acquisition du verrouillage. tryLock renvoie null si le verrou ne peut pas être acquis.

lock()

échantillon de verrouillage


try (FileChannel fileChannel = new FileOutputStream("file-lock-out.txt").getChannel();) {
    FileLock lock = fileChannel.lock();
 System.out.println ("verrou a été obtenu");
 System.out.println ("Gardez le verrou pendant 60 secondes");
    Thread.sleep(60 * 1000);
    lock.release();
} catch (IOException | InterruptedException ex) {
    System.out.println("1" + ex.getMessage());
}

Lorsque ce qui précède est exécuté deux fois avec différents jvm

sortie de jvm1


 J'ai pu obtenir la serrure
 Gardez le verrou pendant 60 secondes

Il n'y a pas de sortie car la sortie de jvm2 attend.

tryLock()

tryLock()échantillon


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

sortie jvm1


 J'ai pu obtenir tryLock

sortie jvm2


lock is null

###Autre 1.Puisque le verrou appartient à jvm, vous ne pouvez pas verrouiller le même fichier avec le même jvm. 2.Sur certaines plates-formes, le verrou est libéré lorsque le FileChannel est fermé. Il n'est donc pas bon d'ouvrir plusieurs FileChannels pour les fichiers verrouillés. 3.Sur certaines plates-formes, les verrous de fichiers sont recommandés et non obligatoires. ⇒ Vous pouvez lire et écrire sans verrou.

#Vient ensuite NIO.2 https://qiita.com/liguofeng29/items/3d0ba350a1547630727b

Recommended Posts

NIO.2 examen de Java
Examen NIO de Java
Avis sur Java Shilber
Notes de révision de Java NIO 2
Revue Java
java IO examen
[Java] Présentation de Java
Collection expirée de java
Caractéristiques prévues de Java
[Java] Importance de serialVersionUID
java --Unification des commentaires
Examen de la classe interne Java
java (mérites du polymorphisme)
Un examen rapide de Java appris en classe
Consultez les annotations Java maintenant
Évaluer java8 ~ Type Lambda ~
[Java] Trois fonctionnalités de Java
Résumé du support Java 2018
Revue Java ③ (utilisation de base des tableaux / type de référence)
Un examen rapide de Java appris en classe part4
[Java] À propos de Objects.equals () et examen de la comparaison de chaînes (== et égal à)
Un examen rapide de Java appris en classe part3
Un examen rapide de Java appris en classe part2
À propos des instances Java
[Java] Utilisation de Mirage-Basic de SQL
[Java] Compréhension débutante de Servlet-②
[Java] Pratique de la gestion des exceptions [Exception]
[Java11] Résumé du flux -Avantages du flux-
Révision et résumé de Progate Java (débutant)
[Java] Création d'annotations originales
[Java] Compréhension débutante de Servlet-①
Java fin du mois plusMonths
[Java] Résumé des expressions régulières
[Java] Résumé des opérateurs (opérateur)
[Java] Implémentation du réseau Faistel
[Java] Comparateur de la classe Collection
Résumé des bases du langage Java
Résumé de la classe Java Math
Énumération de toutes les combinaisons Java
java (héritage du principe is-a)
Avantages et inconvénients de Java
Avantages de la méthode statique Java
[Java] Résumé de la syntaxe de contrôle
Implémentation Java de tri-tree
Résumé du traitement des erreurs Java
[Java] Résumé des modèles de conception
[Java] Résumé des opérations mathématiques
Pensez à une stratégie de mise à jour Java
[Java] Supprimer les éléments de la liste
[Pour les débutants] Résumé du constructeur java
Diverses méthodes de la classe Java String
Cause fondamentale du bogue du framework Java
À propos de Biocontainers fastqc et Java
[Édition Java] Histoire de la sérialisation
Résumé du package [Java Silver Study]
À propos de Lambda, Stream, LocalDate de Java8
Extraction du double hash "ruby" * Avis
Histoire du passage de Java Gold SE8
Trier la liste des objets Java