Le but de ce TP noté est d'écrire quelques classes permettant la gestion de fichiers en mémoire.
Vous vous attacherez à toujours mettre les champs avec des modificateurs
d'accessibilité les plus restreints possibles, à éviter la création d'objet faux
en utilisant judicieusement les pré-conditions, à factoriser le code au maximum,
de sorte à éviter autant que possible toute duplication de code et à ne pas
ajouter de méthodes publiques qui ne sont pas nécessaire par rapport à ce qui est demandé
dans le sujet.
Le but est d'écrire quelques classes/records permettant de gérer des fichiers et répertoires en mémoire.
Un fichier texte (TextFile) est composé d'un nom, d'un contenu (une String) et d'un temps (de type FSTime).
Un répertoire (Folder) est constitué de fichiers textes et de répertoires.
Un temps (FSTime) est composé d'une heure (de 0 à 23) et de minutes (de 0 à 59).
-
Dans un premier temps, on va se concentrer sur la gestion du temps. Pour cela,
on va écrire le code de FSTime qui contient des heures(hour) et des minutes (minute).
On souhaite avoir deux façon de créer un temps, soit en utilisant le constructeur, soit en utilisant
une méthode of comme dans l'exemple ci-dessous. Dans les deux cas, il est interdit de créer
des temps invalides. Et enfin, on veut afficher un temps en utilisant le format HH:MM.
Écrire FSTime de telle façon que le code suivant fonctionne et affiche les bonnes valeurs.
var time = new FSTime(13, 2);
System.out.println(time.hour()); // 13
System.out.println(time.minute()); // 2
System.out.println(time); // 13:02
var time2 = FSTime.of(13, 2);
System.out.println(time2); // 13:02
Note : le format printf correspondant à HH ou MM est %02d et il existe une méthode String.format()
qui prend les mêmes arguments que printf mais renvoie une chaîne de caractères.
-
On souhaite pouvoir comparer deux temps (deux FSTime) en rendant FSTime comparable.
Modifier le code de telle façon que FSTime soit comparable avec lui-même et que le code ci-dessous fonctionne.
var time3 = FSTime.of(8, 23);
var time4 = FSTime.of(13, 13);
var time5 = FSTime.of(8, 8);
System.out.println(time3.compareTo(time4)); // -1
System.out.println(time3.compareTo(time5)); // 1
Rappel : il existe une méthode Integer.compare() qui permet de comparer des entiers entre eux.
-
On souhaite maintenant écrire un TextFile avec un nom (name), un contenu (content) de type String
ainsi qu'un temps (time) de type FSTime.
On souhaite ajouter la possibilité de ne pas spécifier de temps. Dans ce cas, on utilise les heures et minutes du
temps courant à la création de TextFile renvoyé par LocalTime.now().
Écrire TextFile de telle façon que le code suivant fonctionne et affiche les bonnes valeurs.
var textFile = new TextFile("text1.txt", "hello", FSTime.of(6, 45));
System.out.println(textFile.name()); // text1.txt
System.out.println(textFile.content()); // hello
System.out.println(textFile.time()); // 06:45
System.out.println(textFile); // text1.txt
var textFile2 = new TextFile("text2.txt", "hello 2"); // utilise le temps courant
System.out.println(textFile2); // text2.txt
Note : attention à ce qu'il ne soit pas possible de créer un TextFile invalide !
-
On souhaite maintenant créer un Folder qui peut contenir des TextFiles ou des
Folders. À la création, on passe le nom (name) du Folder.
La méthode add permet d'ajouter des TextFiles ou des Folders.
Il ne doit pas être possible d'ajouter des TextFiles ou Folders ayant le même nom.
Il ne doit pas être possible d'ajouter autre chose qu'un TextFiles ou un Folder.
Enfin, l'affichage doit afficher le nom du répertoire suivi d'un espace puis entre parenthèse des
noms des fichiers ou répertoires contenus dans l'ordre d'insertion (dans l'ordre d'appel à add).
Écrire Folder de telle façon que le code suivant fonctionne et affiche les bonnes valeurs.
var folder = new Folder("dir");
var textFile3 = new TextFile("text3.txt", "hello", FSTime.of(3, 3));
folder.add(textFile3);
var textFile4 = new TextFile("text4.txt", "hello 2", FSTime.of(2, 4));
folder.add(textFile4);
//folder.add(textFile3); // java.lang.IllegalStateException: text3.txt already exists
var folder2 = new Folder("subdir");
folder.add(folder2);
System.out.println(folder); // dir (text3.txt, text4.txt, subdir ())
Note : pour la méthode d'affichage d'un répertoire, utilisez un Stream... ou faîtes comme vous voulez
si vous n'y arrivez pas, mais je serai déçu.
Note 2 : pour l'exception, le message d'erreur doit être exactement le même que celui de l'exemple au nom près (
une partie de la correction est automatique).
-
On souhaite maintenant ajouter à Folder une méthode sortedByName qui renvoie
une liste non modifiable de TextFiles et de Folders triés suivant leur nom.
Modifier Folder de telle façon que le code suivant fonctionne et affiche les bonnes valeurs.
var folder3 = new Folder("dir3");
var textFile6 = new TextFile("text6.txt", "six", FSTime.of(6, 6));
var folder4 = new Folder("subdir4");
folder3.add(textFile6);
folder3.add(folder4);
var list = folder3.sortedByName();
System.out.println(list); // [subdir4 (), text6.txt]
Attention : dans la suite du TP, on veut trier de différentes façons... autrement dit, il n'existe pas une façon naturelle d'ordonner des fichiers texte et des répertoires.
Note : il existe une méthode sorted sur un Stream.
Note 2 : attention, la liste renvoyée par sortedByName n'est ni une liste de String ni une liste d'Object
mais une liste de TextFiles ou Folders.
-
On souhaite maintenant ajouter une méthode sortedByContentSize qui, comme sortedByName, renvoie
une liste de TextFiles et de Folders triée, mais en utilisant cette fois-ci, la taille du contenu des
fichiers (c'est à dire la longueur de la String). Pour les répertoires, on utilisera la taille de 0. Dans le cas, où l'on a deux fichiers/répertoires
de même taille, on utilisera l'ordre des noms comme second ordre.
Attention, on ne veut pas qu'une méthode publique contentSize (ou un autre nom) soit ajoutée
à Folder. On se propose, à la place, d'ajouter une méthode statique privée contentSize
qui prend en paramètre un TextFiles ou un Folder et renvoie la bonne valeur.
En terme d'implantation de cette méthode, le plus simple est d'utiliser un switch sur types...
ou si vous n'y arrivez pas, d'affreux instanceofs.
Ajouter la méthode sortedByContentSize et vérifier que le code suivant fonctionne et a le
comportement attendu.
var folder5 = new Folder("dir3");
var textFile7 = new TextFile("text7.txt", "a longer text", FSTime.of(7, 7));
var textFile8 = new TextFile("text8.txt", "a short text", FSTime.of(8, 8));
var folder6 = new Folder("subdir6");
var folder7 = new Folder("subdir7");
folder5.add(textFile7);
folder5.add(textFile8);
folder5.add(folder6);
folder5.add(folder7);
System.out.println(folder5.sortedByContentSize()); // [subdir6 (), subdir7 (), text8.txt, text7.txt]
Note : attention au boxing !
-
En fait, le code pour trier dans sortedByName et dans sortedByContentSize est identique.
On se propose de le factoriser dans une seule méthode sorted et d'écrire deux méthodes statiques
byName() et byContentSize() pour choisir sur quoi le tri va s'effectuer.
Ajouter les méthodes sorted, byName() et byContentSize() de telle façon que le code suivant fonctionne.
var folder8 = new Folder("dir8");
folder8.add(new TextFile("text9.txt", "content of 9", FSTime.of(3, 3)));
folder8.add(new TextFile("text10.txt", "content of 10", FSTime.of(3, 5)));
System.out.println(folder8.sorted(Folder.byName())); // [text10.txt, text9.txt]
System.out.println(folder8.sorted(Folder.byContentSize())); // [text9.txt, text10.txt]
-
Enfin, on souhaite trier d'abord les répertoires par leurs noms puis les fichiers en fonction du temps (et du nom si le temps est identique). Remarquez que donner un taille de 0 ou un temps de FSTime.of(0, 0) aux répertoires ne marchera pas dans le cas où un fichier à soit une taille de 0, soit un temps de FSTime.of(0, 0) (dans ce cas, les fichiers et répertoires pourraient être mélangés).
L'astuce est d'avoir des façons de trier différentes en fonction des types. Pour cela, on va utiliser la fonction de comparaison suivante.
-
Si on a deux répertoires, on compare leurs noms ;
-
si on a deux fichiers, on compare leurs temps puis leurs noms en cas d'égalité ;
-
si on a un répertoire et un fichier, on renvoie -1 et si on a un fichier et un répertoire, on renvoie 1.
Écrire Folder.byTime() qui utilise l'algorithme ci-dessus pour comparer des fichiers et
des répertoires de telle façon que l'on puisse l'utiliser avec sorted() comme ceci.
var folder9 = new Folder("dir9");
folder9.add(new TextFile("text11.txt", "eleven", FSTime.of(17, 3)));
folder9.add(new TextFile("empty.txt", "the content is not empty", FSTime.of(0, 0)));
folder9.add(new Folder("subdir10"));
folder9.add(new Folder("subdir11"));
System.out.println(folder9.sorted(Folder.byTime())); // [subdir10 (), subdir11 (), empty.txt, text11.txt]