Files
SAE32_2025/src/fr/iutfbleau/sae/mpif/BitOutputStream.java
T

152 lines
4.9 KiB
Java
Raw Normal View History

2026-01-07 19:27:03 +01:00
package fr.iutfbleau.sae.mpif;
2025-12-14 18:49:01 +01:00
import java.io.IOException;
import java.io.OutputStream;
/**
* Décorateur de flux permettant l'écriture binaire à granularité du bit.
* <p>
* Cette classe encapsule un {@link OutputStream} existant et permet
* l'écriture de bits individuellement ou par groupes.
* Les bits sont accumulés afin de former des octets avant écriture.
* </p>
* <p>
* Utilisée notamment pour l'encodage des fichiers compressés
* (ex : format PIF utilisant des codes de Huffman).
* </p>
2025-12-17 22:26:49 +01:00
* @author Algassimou Pellel Diallo
* @version 1.0
* @since 2025-12-13
2025-12-14 18:49:01 +01:00
*/
public class BitOutputStream {
/** Flux de sortie sous-jacent */
private final OutputStream fluxSortie;
/** Octet en cours de construction */
private int octetEnConstruction;
/** Position du prochain bit à écrire (de 7 à 0) */
private int positionBit;
/** Indique si le flux est fermé */
private boolean fluxFerme;
/**
* Construit un écrivain binaire à partir d'un flux existant.
*
* @param fluxSortie flux de sortie à décorer
* @throws IllegalArgumentException si le flux est nul
*/
public BitOutputStream(OutputStream fluxSortie) {
if (fluxSortie == null) {
throw new IllegalArgumentException("Le flux de sortie ne peut pas être nul");
}
this.fluxSortie = fluxSortie;
this.octetEnConstruction = 0;
this.positionBit = 7;
this.fluxFerme = false;
}
/**
* Écrit un bit dans le flux binaire.
*
* @param bit bit à écrire (0 ou 1)
* @throws IOException si une erreur d'écriture survient
* @throws IllegalArgumentException si le bit n'est ni 0 ni 1
*/
public void writeBit(int bit) throws IOException {
if (bit != 0 && bit != 1) {
throw new IllegalArgumentException("Le bit doit être 0 ou 1");
}
if (fluxFerme) {
throw new IOException("Le flux de sortie est fermé");
}
if (bit == 1) {
this.octetEnConstruction = this.octetEnConstruction | (1 << this.positionBit);
}
this.positionBit--;
// si on atteint la fin de l'octet, on le grave dans le flux et rebolotte
if(this.positionBit < 0){
this.fluxSortie.write(this.octetEnConstruction);
this.octetEnConstruction = 0;
this.positionBit = 7;
}
}
/**
* Écrit une séquence de bits correspondant à une valeur entière.
*
* @param valeur valeur contenant les bits à écrire
* @param nombreBits nombre de bits à écrire (strictement positif)
* @throws IOException si une erreur d'écriture survient
*/
public void writeBits(int valeur, int nombreBits) throws IOException {
for (int i = nombreBits - 1; i >= 0; i--) {
int bit = (valeur >> i) & 1;
writeBit(bit);
}
}
/**
* Force l'écriture immédiate des données accumulées dans le flux sous-jacent.
*
* @throws IOException si une erreur survient lors du flush
*/
public void flush() throws IOException {
if (fluxFerme) {
throw new IOException("Le flux de sortie est fermé");
}
2026-01-02 20:52:44 +01:00
// Si l'octet nes pas vide on le complete avec des 0
if(this.positionBit < 7){
this.fluxSortie.write(this.octetEnConstruction);
this.octetEnConstruction = 0;
this.positionBit = 7;
2025-12-14 18:49:01 +01:00
}
2026-01-02 20:52:44 +01:00
2025-12-17 22:26:49 +01:00
this.fluxSortie.flush(); // Force l'écriture dans le flux sous-jacent dans le but de vider le buffer
2025-12-14 18:49:01 +01:00
}
2026-01-04 18:05:46 +01:00
/**
* Écrit une séquence de bits à partir d'une chaîne de '0' et '1'.
*
* @param codeBinaire chaîne contenant uniquement '0' et '1'
* @throws IOException si une erreur d'écriture survient
* @throws IllegalArgumentException si la chaîne contient autre chose que '0' ou '1'
*/
public void writeBitString(String codeBinaire) throws IOException {
if (codeBinaire == null) {
throw new IllegalArgumentException("Le code binaire ne peut pas être null");
}
for (int i = 0; i < codeBinaire.length(); i++) {
char c = codeBinaire.charAt(i);
if (c == '0') {
writeBit(0);
} else if (c == '1') {
writeBit(1);
} else {
throw new IllegalArgumentException("Le code binaire ne doit contenir que '0' et '1'");
}
}
}
2025-12-14 18:49:01 +01:00
/**
* Vide les buffers internes et ferme le flux de sortie.
*
* @throws IOException si une erreur survient lors de la fermeture
*/
public void fermerFlux() throws IOException {
// si le flux n'est pas déjà fermé
if (!fluxFerme) {
this.flush(); // compléter l'octet et forcer l'écriture
this.fluxSortie.close(); // fermer le flux sous-jacent
this.fluxFerme = true; // marquer le flux comme fermé
}
}
}