La compression de fichiers par codage de Huffman

publicité
Projet de Développement - PrDv
1
La compression de fichiers par codage de Huffman
1) Le projet
Le but du projet est de réaliser un logiciel de compression de fichiers, comme WinZip ou WinRar,
en utilisant le codage de Huffman1. Le principe du codage de Huffman est de choisir une
représentation de l’information de longueur variable permettant ainsi de représenter des symboles
apparaissant fréquemment par une représentation courte, quitte à ce que certains symboles peu
fréquents disposent, eux, d'une représentation plus longue.
Pour la compression de fichiers, les symboles peuvent être les caractères (ou plus généralement, les
octets) contenus dans le fichier. Pour simplifier la suite, nous parlerons de fichiers textes et de
caractères, même si l'algorithme s'appliquera également aux autres situations.
Le codage de Huffman est donc un codage symbole par symbole, sans perte d’information. Il peut
être montré qu’en ce sens, il est optimal. Tous les logiciels de compression populaires utilisent,
d’une façon ou d’une autre, ce codage.
2) Exercice préparatoire : Entrées/Sorties bit par bit
Une caractéristique d'un programme mettant en œuvre le codage de Huffman pour compresser des
fichiers est la nécessité de lire et d'écrire, dans un fichier, des séquences binaires de longueur
variable. C'est une difficulté particulière car les langages de programmation ne prévoient,
normalement que des Entrées/Sorties (E/S) fixes (ou, éventuellement, des E/S de chaînes de
caractères qui, elles, peuvent être de longueur variable). Tant au niveau des accès mémoire que des
E/S, la plus petite unité adressable des ordinateurs actuels est l'octet (séquence de 8 bits). Toute
donnée est donc normalement représentée par un multiple d'un octet. Ce n'est plus le cas pour un
codage de Huffman. Nous aurons donc besoin de nous construire une librairie de routines, capable
de traiter, un bit à la fois, les informations en E/S. Nous allons donc faire de l'algèbre binaire.
Les opérateurs binaires
Le langage Pascal, comme la plupart des langages de programmation, dispose de plusieurs
opérateurs permettant de faire de l'algèbre binaire. En Pascal, certains de ces opérateurs s'écrivent
de la même façon que les opérateurs logiques que vous connaissez. Attention de ne pas les
confondre : Les opérateurs logiques s'appliquent à des opérandes Booléens alors que les opérateurs
binaires s'appliquent aux entiers. Les opérateurs binaires sont :
2.1
Opérateur
Opération
Exemple
not
Négation binaire (inversion de chaque bit)
not x
and
Et bit à bit (bit résultat à 1 ssi les 2 bits correspondants le sont)
x and y
or
Ou bit à bit (bit résultat à 0 ssi les 2 bits correspondants le sont)
x or y
xor
Ou exclusif bit à bit (bit résultat à 0 ssi les 2 bits correspondants sont égaux) x xor y
shl
Décalage binaire vers la gauche d'un certain nombre de bits
x shl y
shr
Décalage binaire vers la droite d'un certain nombre de bits
x shr y
1
http://fr.wikipedia.org/wiki/Codage_de_Huffman
EPFC - ULB
Bachelier en Informatique 2012
Projet de Développement - PrDv
2
Par exemple si x est un Byte (entier non-signé stocké sur un octet et prenant des valeurs de 0 à 255)
de valeur 202 (binaire : 11001010) et y de valeur 172 (binaire 10101100), alors, l'opération
x And y donnera :
11001010
10101100
————————
And 10001000
C'est-à-dire le résultat 136.
En C++ et en C#, les opérateurs correspondants sont : ~ (not), & (and), | (or), ^ (xor), << (shl) et
>> (shr).
En Java, utilisez les opérateur semblables. Attention, en Java, utilisez >>> pour le décalage à droite
(et pas >>).
Pour d'autres langages, voyez le manuel de référence.
Dans un langage qui le permet, veillez à utiliser des entiers non-signés (Byte, Word, LongWord en
Pascal).
Manipulation des fichiers en Pascal
Un programme ByteCopy.pas vous est fourni pour vous illustrer la manipulation des fichiers en
Pascal. Ce programme recopie, octet par octet, le contenu d'un fichier. Vous y verrez l'usage des
routines d'E/S du Pascal :
2.2
•
AssignFile qui associe une variable fichier à son nom externe
•
Reset qui ouvre un fichier existant
•
Rewrite qui crée et ouvre un nouveau fichier
•
Read et Write qui permettent de lire et d'écrire dans un fichier
•
FileSize qui renvoie la taille d'un fichier
•
CloseFile qui ferme un fichier (et vide son tampon)
Pour les autres langages, reportez-vous au manuel de référence. Un programme ByteCopy.java
vous est aussi fourni pour illustrer une façon possible, en Java, de recopier, octet par octet, le
contenu d’un fichier.
Une librairie d'E/S bit par bit
L'algorithme de Huffman nécessitera d'écrire, bit par bit, le résultat du codage dans le fichier
compressé. Il s'agira aussi, plus tard, de relire bit par bit les information dans le fichier compressé
pour reconstruire le fichier d'origine.
2.3
Bien sûr, il n’est pas question de lire et d’écrire vraiment un bit à la fois dans un fichier. L’idée est
donc d’utiliser un tampon (une variable intermédiaire) de 1 octet. Par exemple, pour l’écriture dans
un fichier, chaque écriture d’un bit ne fera que mémoriser la valeur du bit dans le tampon. Ce n’est
que lorsque le tampon sera plein (c’est-à-dire que 8 bits y auront été ajoutés) que le tampon sera
écrit dans le fichier et réinitialisé afin d'être ainsi prêt à recevoir les bits suivants à écrire dans le
fichier. Un processus similaire est utilisé pour la lecture.
EPFC - ULB
Bachelier en Informatique 2012
Projet de Développement - PrDv
3
Au minimum, vous devrez donc réaliser une librairie (unité en Pascal) dont l'Interface est la
suivante :
Unit BitFile;
Interface
// Un fichier qu'on traite un octet à la fois
Type FichierBit = ... // A vous de compléter
// Crée l'association du fichier f avec son NomFich
Procedure AssocieNomFich(Var f: FichierBit; Const NomFich: String);
// Préparation du fichier pour une lecture bit à bit.
// Initialise le tampon de lecture
Procedure InitFichLecture(Var f: FichierBit);
// Préparation du fichier pour une écriture bit à bit.
// Initialise le tampon de d'écriture
Procedure InitFichEcriture(Var f: FichierBit);
// Ecriture du bit dans le (tampon du) fichier f
Procedure EcrireBit(Var f: FichierBit; bit: Byte);
// Ecriture de l'octet (8 bits) dans le (tampon du) fichier f
Procedure EcrireByte(Var f: FichierBit; octet: Byte);
// Lecture d'un bit à partir du (tampon du) fichier f
Procedure LireBit(Var f: FichierBit; Var bit: Byte);
// Lecture d'un octet (8 bits) à partir du (tampon du) fichier f
Procedure LireByte(Var f: FichierBit; Var octet: Byte);
// Vidage final du tampon du fichier f
Procedure ClotureEcriture(Var f: FichierBit);
A nouveau, un programme BitCopy.pas vous est fourni pour illustrer l'usage de la librairie
BitFile et qui recopie, bit par bit, le contenu d'un fichier (texte), cette fois, en ajoutant une ligne de
début et une de fin. Le programme pourra vous servir à tester votre implémentation de l’unité
BitFile.
Si vous décidez d’utiliser un autre langage de programmation, vous concevrez une librairie
similaire, appropriée à votre langage. Vous êtes libre de choisir un design qui utilise les
constructions du langage de votre choix (Classes, Interfaces, Méthodes…) pour autant que vous
respectiez l’idée des fonctionnalités offertes par l’unité Pascal ci-dessus.
EPFC - ULB
Bachelier en Informatique 2012
Téléchargement