Lecture et écriture de bits en Java

Introduction

Dans ce TP on va écrire des classes contenant des méthodes permettant de lire et d'écrire dans un fichier bit à bit. Il s'agit d'une simulation car les lectures et les écritures se font en fait par octets. Ces opérations sont nécessaires quand on implémente des méthodes de codage et de décodage sur des fichiers.

Avant de commencer

Les classes FileInputStream et FileOutputInputStream (dans java.io) définissent des flots permettant la lecture et l'écriture de fichiers de bits. Regardez la documentation de ces classes sur la plate-forme. Regardez particulièrement la méthode int read() de FileInputStream et void write(int b) de FileOutputStream.

La méthode int read() contrairement à ce que l'on pourrait penser ne lit pas un entier. Elle lit un octet (un << byte >>) qu'elle retourne comme étant un entier compris entre 0 et 255 dont l'octet de poids faible est l'octet lu. Symétriquement la méthode void write(int b) n'écrit pas n'importe quel entier mais écrit un byte que l'on transmet en paramètre comme octet de poids faible d'un int.

Partie lecture

Dans cette partie on va s'occuper de la lecture des bits. On différentie la lecture de l'écriture car on fait rarement les deux opérations en même temps (sauf dans les pipe).

Créer une classe BitInputStream qui étend FilterInputStream avec son constructeur.

Écrire une méthode int readBit() qui permet de lire un bit dans le flot. La valeur retournée est un entier qui vaut 0 ou 1. Lorsque la fin du fichier est atteinte, on retourne l'entier -1.

Au départ on lit un octet à l'aide de la méthode int read() de FileInputStream que l'on stocke sous forme d'un int de nom bits. Chaque fois que la lecture d'un bit est demandée on fournit un bit de cet octet que l'on ne prend plus en compte à la demande suivante. Lorsque les 8 bits de l'octet on été lus, on lit à la demande suivante un nouvel octet du flot.

Pour repérer le bit de l'entier bits qui doit être pris en compte, on peut utliser un masque entier mask qui indique la position de ce bit. Au départ le masque sera l'entier dont le dernier octet est 10000000, soit 128, dont le code hexadécimal est 0x80 (pourquoi ?). Une fois le bit lu, on décale le bit 1 du masque d'un cran à droite.

Partie écriture

Pour l'écriture des bits, créer une classe BitOutputStream qui étend FilterOutputStream avec son constructeur. Les bits à écrire seront stockés dans le dernier octet d'un entier bits. Le nombre de bits déjà stockés est mémorisé dans un entier offset.

Lorsque l'utilisateur demande l'écriture d'un bit,

Écrire une méthode void writeBit() qui permet d'écrire un bit dans le flot.

Écrire une méthode void flush() qui permet d'écrire les bits restant dans bits même lorsqu'ils sont moins de 8. On complète alors par des 0.

Écrire une méthode void close() qui permet de refermer le flot en écriture. On appelle flush() avant la fermeture.

Tests et documentation

Tester vos classes en écrivant une classe Main.java qui crée un fichier, écrit 5 bits dedans, le referme et essaye de lire ensuite 9 bits qui seront affichés sous forme d'entiers à l'écran.

Créer une documentation avec des tags javadoc pour ces classes. Pour compiler la documentation lancer javadoc *.java. Pour la visualiser lancer Netscape sur index.html.

Solutions après le TP Main.java, BitInputStream.java, BitOutputStream.java.