Introduction
Une archive peut contenir des images identiques portant des noms différents et des images différentes de même taille. Vous allez réaliser la lecture des octets d'un outil réutilisable de recherche de doublons et enregistrer un inventaire complet sans modifier les originaux.
Vous devez connaître les classes, méthodes, listes, exceptions et la lecture élémentaire de fichiers en Java. Ce laboratoire présente l'entrée binaire, la fermeture automatique des ressources et SHA-256. L'adaptateur de répertoire et le lanceur sont fournis ; vous implémentez l'empreinte. Il s'agit d'un exercice en lecture seule, pas d'un outil de nettoyage de disque. L'auteur estime 50 minutes, lecture et corrections courantes comprises.
Lire les octets plutôt que le nom
Dans cette étape, vous comparerez un exemple normal d'images, puis implémenterez une empreinte qui lit chaque octet exactement une fois. Ouvrez WebIDE, choisissez Terminal > New Terminal, puis utilisez ce terminal intégré pendant tout le laboratoire. Chaque laboratoire démarre indépendamment avec ses propres fichiers.
cd change le répertoire de travail de ce terminal. Le script fourni run.sh compile src/*.java dans un nouveau répertoire temporaire de compilation, puis exécute la classe Java indiquée. Le compilateur utilise -encoding UTF-8 pour que le texte source ne dépende pas des paramètres régionaux du terminal. Seuls le compilateur et les processus Java enfants utilisent C.UTF-8 ; le processus Java utilise également UTF-8 par défaut pour le texte, ce qui permet les noms UTF-8 pris en charge sans modifier votre shell.
cd /home/labex/project/duplicates
./run.sh Sample
L'auxiliaire décode les vrais fichiers PNG et compare leurs octets. Il affiche red = renamed: true et red = blue: false. Les trois images ont les mêmes dimensions et la même longueur en octets. Un nom ou une longueur peuvent réduire la recherche, mais ne prouvent pas l'égalité. Facultativement, dans WebIDE Explorer, développez duplicates/data/gallery et cliquez sur red.png, blue.png et copies/renamed.png pour afficher les images. La comparaison obligatoire repose sur le décodage et le résultat en octets de Sample ci-dessus. Ce sont des images synthétiques originales du cours ; aucune ressource externe n'est nécessaire.
L'interface publique Digester définit une méthode : digest(Path) renvoie une chaîne hexadécimale ou lève IOException si la lecture échoue. Path identifie un fichier ; un InputStream lit des octets binaires sans les interpréter comme du texte. SHA-256 condense ces octets en une empreinte candidate de longueur fixe. Une unité ultérieure comparera encore le contenu réel avant de déclarer des doublons.
Lisez le petit adaptateur et le code initial avant de remplacer ce dernier :
cat src/Digester.java src/Sha256.java
Un tampon de 1024 octets est réutilisé. read(buffer) renvoie le nombre d'octets valides de cette lecture, ou -1 à la fin. La dernière lecture peut ne remplir qu'une partie du tampon : les octets restants gardent des valeurs précédentes. C'est pourquoi sha.update(buffer, 0, count) doit utiliser le nombre réellement lu. Un fichier vide ne provoque aucune mise à jour et possède néanmoins une empreinte valide.
try (InputStream ... ) correspond à try-with-resources : Java ferme le flux à la fin du bloc, y compris si la lecture lève une exception. La fermeture libère la ressource fichier ; elle ne garantit pas un passage immédiat du ramasse-miettes. MessageDigest.getInstance peut lever une exception vérifiée liée à l'algorithme ; le catch externe la convertit donc vers le même contrat d'erreur d'opération sur fichier. L'hexadécimal utilise deux caractères par octet ; & 255 interprète un octet Java signé comme sa valeur non signée.
La commande suivante écrit le remplacement complet. > remplace ce fichier source. Le marqueur here-document entre guillemets <<'JAVA' transmet littéralement à cat le texte intermédiaire ; le JAVA final doit être seul sur sa ligne, sans retrait. Vous pouvez aussi modifier puis enregistrer ce fichier dans WebIDE. Si, après le collage, le terminal reste sur l'invite d'un here-document inachevé, appuyez sur Ctrl+C pour annuler, puis recollez toute la commande, marqueur final compris.
cat > src/Sha256.java <<'JAVA'
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Sha256 implements Digester {
public String digest(Path path) throws IOException {
try {
MessageDigest sha = MessageDigest.getInstance("SHA-256");
byte[] buffer = new byte[1024];
try (InputStream input = Files.newInputStream(path)) {
int count;
while ((count = input.read(buffer)) != -1) {
sha.update(buffer, 0, count);
}
}
StringBuilder hex = new StringBuilder();
for (byte value : sha.digest()) {
hex.append(String.format("%02x", value & 255));
}
return hex.toString();
} catch (NoSuchAlgorithmException error) {
throw new IOException("SHA-256 unavailable", error);
}
}
}
JAVA
Recompilez et exécutez le même exemple. La compilation vérifie la nouvelle classe ; les décisions d'égalité de l'exemple restent inchangées.
./run.sh Sample
Si Java indique un numéro de ligne, rouvrez src/Sha256.java, comparez les accolades et l'orthographe avec le remplacement, enregistrez puis réessayez. Si un chemin est incorrect, utilisez pwd pour voir le répertoire actuel, puis répétez le cd absolu ci-dessus. Il n'est pas nécessaire de réinitialiser la VM.
Enregistrer chaque chemin et son empreinte
Dans cette étape, vous utiliserez votre empreinte pour créer un inventaire UTF-8 complet. Continuez dans le même terminal intégré de WebIDE, dans /home/labex/project/duplicates.
L'adaptateur fourni Inputs.files parcourt uniquement le répertoire indiqué et ferme son flux de répertoire. Il refuse les liens symboliques, les fichiers spéciaux et les chemins contenant des tabulations ou retours à la ligne, au lieu de les suivre ou de les ignorer silencieusement. Seuls les fichiers et répertoires ordinaires stables sont pris en charge. Ne modifiez pas les entrées pendant l'analyse. Les contrôles d'attributs détectent certains changements, mais ne figent pas le répertoire et ne garantissent pas d'instantané concurrent.
Le programme fourni Inventory enregistre chaque chemin relatif, taille et empreinte après la réussite de toutes les lectures. Son format TSV sépare les colonnes par une tabulation. L'adaptateur de rapport écrit du texte UTF-8 dans un nouveau fichier temporaire, puis remplace le chemin du rapport ; même un rapport existant sous forme de lien physique ne peut donc pas écraser les octets originaux. Cela ne garantit pas la durabilité après un plantage. La sortie doit se trouver hors de la racine analysée. reports existe déjà à côté de data, empêchant le rapport de devenir sa propre entrée. La commande suit l'ordre Inventory ROOT REPORT : le premier argument est le répertoire à analyser, le second le chemin de sortie ; ne les inversez pas.
./run.sh Inventory data/gallery reports/inventory.tsv
Le résultat attendu est Inventory complete: 11 files. cat affiche le texte enregistré :
cat reports/inventory.tsv
L'en-tête est PATH, SIZE, SHA256. Comparez les lignes de red.png, copies/renamed.png et copies/third.png : des chemins différents partagent une empreinte. blue.png a la même taille, mais une autre empreinte. Les deux fichiers vides ont une taille nulle et la même empreinte valide. tail.bin finit par un tampon partiel ; sa copie identique doit recevoir la même empreinte. Les fichiers de même nom north/readme.txt et south/readme.txt conservent des lignes distinctes.
Exercez-vous maintenant à une erreur de chemin courante. La commande suivante échoue volontairement avec le code de sortie 2 et Scan failed ; elle ne doit pas produire de nouveau rapport. Un échec n'est pas un inventaire vide réussi. Un rapport plus ancien ne prouve pas la réussite de cette exécution échouée.
./run.sh Inventory data/missing reports/missing.tsv
Corrigez le chemin d'entrée et créez un nouveau rapport :
./run.sh Inventory data/gallery reports/recovered.tsv
Les erreurs de lecture suivent la même règle : affichez l'erreur et renvoyez un échec, sans omettre silencieusement un fichier illisible. Les vérifications exécutent votre code actuel sur des jeux de test isolés vides, à tampon partiel et illisibles, puis lisent le vrai inventaire. Tous les originaux doivent conserver leurs chemins, octets, permissions, propriétaires et dates de modification ; ne les supprimez ni ne les remplacez. Les lectures ordinaires peuvent mettre à jour les dates d'accès. Vous disposez désormais de faits candidats ; dans le prochain laboratoire, les empreintes égales serviront de candidats à une comparaison réelle des octets.
Résumé
Vous avez lu des fichiers binaires avec try-with-resources, alimenté SHA-256 avec le nombre réellement lu et enregistré un inventaire UTF-8 complet. Les noms, tailles et empreintes sont des faits candidats ; la comparaison des octets réels confirmera les groupes de doublons.



