Les tampons MappedByteBuffer possèdent la particularité de manipuler les données d'un fichier uniquement au travers de la mémoire. Ainsi, un fichier mappé en mémoire (Memory-mapped file) signifie que le canal envoie directement les données du fichier vers la mémoire de l'ordinateur, à partir de laquelle toutes les opérations d'enrée/sortie seront réalisées. Cette méthode améliore donc considérablement les performances des opérations de lecture et d'écriture sur un fichier, puisqu'elle ne nécessiterait aucun accès sur le disque dur. L'implémentation exacte de la technique des MappedByteBuffer dépend de la plateforme sous-jacente.

La création d'un objet MappedByteBuffer nécessite l'invocation de la méthode map() à partir d'un objet FileChannel.

File fichier = new File("c:\\source.txt");
RandomAccessFile raf= new RandomAccessFile(fichier, "rw");
FileChannel canal= raf.getChannel();
MappedByteBuffer tampon= 
        canal.map(FileChannel.MapMode.READ_WRITE, 0, fc.size());

La méthode map() prend trois arguments. Les deux derniers sont des entiers longs représentant la position initiale du bloc de données à charger en mémmoire, et la taille de ce bloc. Un fichier peut être entièrement ou partiellement mappé en mémoire.

MappedByteBuffer tampon = 
        canal.map(FileChannel.MapMode.READ_WRITE, 512, 1024);

Le premier argument est une constante fournie par la classe imbriquée FileChannel.MapMode. Cette classe propose trois champs statiques impliquant un mode d'accès à un fichier mappé :

  • READ_ONLY : Accès en lecture seule.
  • READ_WRITE : Accès en lecture et écriture.
  • PRIVATE : Accès en privé (copy-on-write).

Un tampon MappedByteBuffer reste disponible tant qu'il n'a pas été fermé (close()) puis nettoyé par le collecteur de déchets (Garbage Collector). Ceci implique des précautions d'emplois, notamment lorsqu'un fichier mappé est ouvert par un programme, un autre programme ou un processus concurrent dans le même programme ne peut pas accéder à la totalité ou à la portion du fichier mappé. En conséquence, toutes tentatives d'accéder à un fichier mappé provoquera la levée d'une exception dépendant du système d'exploitation sous-jacent.

La classe MappedByteBuffer descendant de la classe ByteBuffer se comporte de la même façon qu'un tampon d'octets direct. Toutefois, trois méthodes supplémentaires sont proposées pour s'assurer d'un fonctionnement correct en mémoire.

La méthde load() charge le contenu du tampon en mémoire et retourne un objet MappedByteBuffer. L'effectivité du chargement en mémoire peut être contrôlée par la méthode isLoaded().

if(!tampon.isLoaded())
    tampon = tampon.load();

Suite à une modification du contenu d'un objet MappedByteBuffer avec un mode en lecture et écriture (FileChannel.MapMode.READ_WRITE), la méthode force() peut être utilisée pour forcer les changements à être écrit sur le périphérique de stockage contenant le fichier mappé.

//Modification du tampon...
byte o = 124;
tampon = tampon.put(o);
//Validation des modifications
tampon = tampon.force();
Exemple [voir]
package nio;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;

public class Fichier extends File {
    private FileChannel fc;
    private MappedByteBuffer mpb;
    private CharsetEncoder encodeur;
    private CharsetDecoder decodeur;

    public static void main(String[] args) {
        Fichier fichier = new Fichier("fichier.txt", "ISO-8859-1");
        fichier.ecrire("Un contenu quelconque...");
        System.out.println(fichier.lire());
        fichier.fermer();
    }
    public Fichier(String chemin, String encodage) {
        super(chemin);
    try{
        RandomAccessFile raf = new RandomAccessFile(this, "rw");
        fc = raf.getChannel();
        Charset latin = Charset.forName(encodage);
        encodeur = latin.newEncoder();
          decodeur = latin.newDecoder();
        mpb = fc.map( FileChannel.MapMode.READ_WRITE, 0, 1024);
    }
    catch (IOException e) {
      e.printStackTrace();
    }
        
    }
  public void ecrire(String contenu){
      try {
        mpb.limit(contenu.length());
        CharBuffer cb = CharBuffer.wrap(contenu);
          ByteBuffer bb = encodeur.encode(cb);
        mpb.put(bb);
        }
        catch (CharacterCodingException e) {
            e.printStackTrace();
        }
  }
  public String lire(){
        try {
            mpb.position(0);
            CharBuffer cb = decodeur.decode(mpb);
          return cb.toString();
        }
        catch (CharacterCodingException e) {
            e.printStackTrace();
        }
        return null;
  }
  public void fermer() {
      try {
            this.fc.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
  }
}