Les canaux s'obtiennent par l'intermédaire des méthodes getChannel() d'objets FileInputStream, FileOutputStream, ou RandomAccessFile pour les fichiers et ServerSocket, Socket pour les ressources provenant des réseaux.
FileInputStream fis = new FileInputStream(new File("chemin")); FileChannel fc = fis.getChannel(); ServerSocket ss = new ServerSocket(8080); ServerSocketChannel fc = ss.getChannel();
Un canal est dit ouvert lors de sa création. La fermeture de ce canal s'obtient suite à l'invocation de la méthode close(). Si un objet Channel est fermé, toutes tentatives d'y accèder provoquera la levée d'une exception ClosedChannelException. Afin d'éviter ce problème, il faut utiliser la méthode isOpen() pour tester si le canal concerné est encore disponible pour des opérations d'entrée/sortie.
if(fc.isOpen()){ ByteBuffer buf = ByteBuffer.allocate(fc.size()); fc.read(buf); fc.close(); }
L'ouverture des objets SocketChannel est aussi réalisable au moyen des méthodes open() disponibles dans les classes SocketChannel et ServerSocketChannel.
ServerSocketChannel ssc = ServerSocketChannel.open();
Les canaux disposent de plusieurs méthodes de lecture et d'écriture. Les interfaces ReadableByteChannel et WritableByteChannel fournissent respectivement une méthode read() et une autre write() permettant de lire et d'écrire dans un tampon d'octets (ByteBuffer). Ces deux méthodes implémentées dans les classes DatagramChannel, FileChannel, Pipe.SourceChannel et SocketChannel, retournent le nombre d'octets lus ou écrits.
int nb = 0; while ((nb = fc_entree.read(buf)) == -1){ buf.flip(); fc_sortie.write(buf); buf.clear(); }
Si le canal est ouvert en lecture seule, une tentative d'écriture provoquera la levée d'une exception NonWritableChannelException, et inversement si le canal n'est pas ouvert en lecture, sera lancée une exception NonReadableChannelException.
Un canal ouvert à partir d'un objet FileInputStream, il est dit ouvert en lecture. Pour un flux FileOutputStream, le canal est ouvert en écriture. Dans le cas d'un objet RandomAccessFile, le type d'ouverture dépend du mode d'accès (r : lecture seule, w : écriture seule, rw : lecture et écriture) spécifié au moment de la création de l'objet. En ce qui concerne les sockets réseau, les canaux sont bidirectionnels.
FileInputStream fis = new FileInputStream("chemin_fichier"); FileOutputStream fos = new FileOutputStream("chemin_fichier"); RandomAccessFile raf = new RandomAccessFile("chemin_fichier", "rw"); FileChannel fc_lecture = fis.getChannel(); FileChannel fc_ecriture = fos.getChannel(); FileChannel fc_lecture_ecriture = raf.getChannel();
Les interfaces GatheringByteChannel et ScatteringByteChannel fournissent des méthodes d'écriture et de lecture sur des tableaux d'objets ByteBuffer. La méthode Gathering/Scattering IO (Assemblage/Division IO) permet de manipuler plusieurs tampons d'octets.
RandomAccessFile raf= new RandomAccessFile("chemin_fichier", "rw"); FileChannel canal = raf.getChannel(); ByteBuffer[] tampons = new ByteBuffer[10]; //Méthodes Gathering IO long nb_octets = canal.write(tampons); long nb_octets = canal.write(tampons, 0, 1024); //Méthodes Scattering IO long nb_octets = canal.read(tampons); long nb_octets = canal.read(tampons, 0, 1024);
Ces méthodes de lecture et d'écriture sont utiles par exemple, pour diviser ou assembler un message réseau reçu ou à envoyer via un canal. Les deux deux parties distinctes d'une requête ou d'une réponse, l'entête et le corps, peuvent dans ce cadre être stockés dans deux objets ByteBuffer qui seront soumis à ce genre de méthode.
Exemple [voir]package nio; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class Copie { public static void main(String args[]) { File source = new File("source.txt"); File destination = new File("destination.txt"); Copie copie = new Copie(); copie.copier(source, destination, true); } public void copier(File fic_source, File fic_destination, boolean rapide) { try { FileInputStream fis_source = new FileInputStream(fic_source); FileOutputStream fos_destination = new FileOutputStream(fic_destination); FileChannel fc_source = fis_source.getChannel(); FileChannel fc_destination = fos_destination.getChannel(); ByteBuffer tampon = null; if(rapide) tampon = ByteBuffer.allocateDirect(1024); else tampon = ByteBuffer.allocate(1024); int nb_octets = 0; while ((nb_octets = fc_source.read(tampon)) > -1) { tampon.flip(); fc_destination.write(tampon); tampon.clear(); } } catch(IOException e) { e.printStackTrace(); } } } |