14.    Gestion des fichiers (nio2)











Dans la version 4 de Java un nouveau modèle a été introduit (nio - new input/output). Ce modèle a été totalement refait dans la version 7 (nio2). Les classes de ces modèles sont placées dans le package java.nio. Le nouveau modèle est basé sur les tampons (buffers) et canaux (channels). Les deux modèles (les flux et nio2) ont leurs atouts et défauts dans des situations différentes.

14.1    La classe Path 



14.1.1      Définition

On peut créer un objet de la classe en utilisant la méthode get() de la classe utilitaire Paths avec paramètre – le chemin absolu ou relatif.

Path path = Paths.get("Test.txt");                                    // dans le répertoire corrant
Path path = Paths.get("D:\\data\\Test.txt");                  // système de fichiers Windows
Path path = Paths.get("/home/data/Test.txt");             // système de fichiers Unix

14.1.2      Opérations syntactiques

L'exemple suivant montre quelques opérations syntactiques. Elles sont assez intuitives.

import java.nio.file.Path;
import java.nio.file.Paths;
public class PathInf {
    public static void main(String arg[]){
        Path absPath = Paths.get("D:\\iv\\dt\\sys\\Test.txt");  //windows файлова система
        System.out.format("absolute Path %n");
        System.out.format("toString: %s%n",absPath.toString());
        System.out.format("getFileName: %s%n", absPath.getFileName());
        System.out.format("getNameCount: %d%n",absPath.getNameCount());
        for(int i=0; ;i++){
            try{
                System.out.format("getName(%d): %s%n", i,absPath.getName(i));
            }catch(IllegalArgumentException ex){
                System.out.format("no more names %n");
                break;
            }
        }
        System.out.format("subpath(0,2): %s%n",absPath.subpath(0,2));
        System.out.format("getParent: %s%n",absPath.getParent());
        System.out.format("getRoot: %s%n",absPath.getRoot());
        Path relPath = Paths.get("dt\\sys\\Test.txt");
        System.out.format("%n relative Path %n");
        System.out.format("toString: %s%n",relPath.toString());
        System.out.format("getFileName: %s%n", relPath.getFileName());
        System.out.format("getName(0): %s%n", relPath.getName(0));
        System.out.format("getNameCount: %d%n",relPath.getNameCount());
        for (Path name : relPath) {     System.out.format("Name: %s%n",name);    }
        System.out.format("subpath(0,2): %s%n",relPath.subpath(0,2));
        System.out.format("getParent: %s%n",relPath.getParent());
        System.out.format("getRoot: %s%n",relPath.getRoot());
    }
}





14.2    Les tampons



Le tampon représente un tableau. Le plus souvent est utilisé un tableau des octets – ByteBuffer, mais on peut utiliser des classes dérivées de la classe Buffer pour la plupart des types primitifs – CharBuffer, IntBuffer, ShortBuffer, LongBuffer, FloatBuffer et DoubleBuffer

14.2.1      Paramètres


•    position
la place d’où on peut lire ou dans laquelle on peut lire information. On peut la consulter et modifier par
public final int position( )
public final Buffer position(int newPosition)
•    capacitéle nombre maximal d'éléments dans le tampon, consulté par
public final int capacity( )
•    limitela dernière position où on peut lire et écrire les données, consultées et modifiées par
public final int limit( )
public final Buffer limit(int newLimit)
•    MarkPour mémoriser une position. Avec la méthode mark() on la met à la position courante. Avec reset() on fait la position courante égale au mark.
public final Buffer mark( )
public final Buffer reset( )


14.2.2      Création

 Les tampons vides :
ByteBuffer buffer1 = ByteBuffer.allocate(100);
IntBuffer  buffer2 = IntBuffer.allocate(100);

On peut obtenir une référence de type tableau sur le tampon par
byte[] data1 = buffer1.array();

Dans les opérations de sortie on fait un tampon comme enveloppe sur l'information à écrire.
int[] data = {1, 3, 2, 4, 23, 53, -9, 67};
IntBuffer buffer = IntBuffer.wrap(data);



14.2.3      L'accès aux données

public abstract byte get()
public ByteBuffer get(byte[] dst)
public ByteBuffer get(byte[] dst, int offset, int length)
public abstract byte get(int index)
public abstract ByteBuffer put(byte b)
public final ByteBuffer put(byte[] src)
public ByteBuffer put(byte[] src, int offset, int length)
public ByteBuffer put(ByteBuffer src)
public abstract ByteBuffer put(int index, byte b)
public abstract char getChar()
public abstract char getChar(int index)
public abstract double getDouble()
public abstract double getDouble(int index)
public abstract float getFloat()
public abstract float getFloat(int index)
public abstract int getInt()
public abstract int getInt(int index)
public abstract long getLong()
public abstract long getLong(int index)
public abstract short getShort()
public abstract short getShort(int index)
public abstract ByteBuffer putChar(char value)
public abstract ByteBuffer putChar(int index, char value)
public abstract ByteBuffer putDouble(double value)
public abstract ByteBuffer putDouble(int index, double value)
public abstract ByteBuffer putFloat(float value)
public abstract ByteBuffer putFloat(int index, float value)
public abstract ByteBuffer putInt(int value)
public abstract ByteBuffer putInt(int index, int value)
public abstract ByteBuffer putLong(int index, long value)
public abstract ByteBuffer putLong(long value)
public abstract ByteBuffer putShort(int index, short value)
public abstract ByteBuffer putShort(short value)




14.3    Les canaux



14.3.1      Les interfaces


14.3.2      Exemple

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class CopyNio {
    public static void main(String[] args) throws IOException {
        FileInputStream inFile = new FileInputStream(args[0]);
        FileOutputStream outFile = new FileOutputStream(args[1]);
        FileChannel inChannel = inFile.getChannel( );
        FileChannel outChannel = outFile.getChannel( );
        ByteBuffer buffer = ByteBuffer.allocate(4096);
        byte data[] = buffer.array();
        for (; inChannel.read(buffer) != -1; buffer.clear( )) {
            for (int i=0;i<data.length;i++){
                if (data[i] == 't'){     data[i] = 's';  }
            }
            buffer.flip( );
            while (buffer.hasRemaining( )) {
                outChannel.write(buffer);
            }
        }
        inChannel.close( );           outChannel.close( );
    }
}




14.4    Les fichiers à l'accès direct



L'exemple: un accès direct avec la lecture d'information au début, au milieu et à la fin du fichier, avec un tampon 5 octets

import java.io.IOException;
import java.nio.*;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.*;
import java.util.EnumSet;
public class RafRead {
    public static void main(String[] args) {
        int bufLen=5;
        Path path = Paths.get("Test.txt");
        ByteBuffer buf = ByteBuffer.allocate(bufLen);
        String encoding = System.getProperty("file.encoding");
        try (SeekableByteChannel sbc = (Files.newByteChannel(
                path, EnumSet.of(StandardOpenOption.READ)))) {
            System.out.println("the size of the file is "+sbc.size());
            sbc.position(0);
            System.out.println("\nReading "+bufLen+" character from position: " + sbc.position());
            do{     sbc.read(buf);       }  while(buf.hasRemaining());
            buf.flip();
            System.out.print(Charset.forName(encoding).decode(buf));
            buf.rewind();

            // lecture au milieu
            sbc.position(sbc.size() / 2);
            System.out.println("\nReading "+bufLen+" character from position: "+ sbc.position());
            do{  sbc.read(buf);         }  while(buf.hasRemaining());
            buf.flip();
            System.out.print(Charset.forName(encoding).decode(buf));
            buf.rewind();

            // fin de fichier
            sbc.position(sbc.size() - bufLen);
            System.out.println("\nReading "+bufLen+" character from position: " + sbc.position());
            do{  sbc.read(buf);     }     while(buf.hasRemaining());
            buf.flip();
            System.out.print(Charset.forName(encoding).decode(buf));
            buf.clear();
        } catch (IOException ex) {        System.err.println(ex);    }
    } 
}


L'exemple suivant lit les premiers 10 octets d'un fichier texte Test.txt et les écrit sur une nouvelle ligne à la fin du fichier.

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
public class RafRW {
    public static void main(String[] args) {
        Path path = Paths.get("Test.txt");
        ByteBuffer bf = ByteBuffer.allocate(10);
        bf.put("\n".getBytes());
        try (SeekableByteChannel sbc = (Files.newByteChannel(path,
                EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE)))) {
            bf.flip();
            sbc.position(sbc.size());
            while (bf.hasRemaining()) {
                sbc.write(bf);
            }
            bf.clear();
            sbc.position(0);
            do {  sbc.read(bf); } while (bf.hasRemaining());
            bf.flip();
            sbc.position(sbc.size());
            while (bf.hasRemaining()) {
                sbc.write(bf);
            }
            bf.clear();
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }
}