:: Enseignements :: ESIPE :: E3INFO :: 2021-2022 :: Programmation Objet avec Java ::
[LOGO]

Examen de Java - Session 2


Le but de ce TP noté est d'écrire quelques classes permettant la gestion de fichiers en mémoire.

À lire absolument

Tout ce que vous devez rendre devra obligatoirement être placé dans le répertoire EXAM à la racine de votre compte ; sinon, ce n'est pas récupéré et vous aurez 0.

Tout document papier est proscrit.
La javadoc 17 est https://igm.univ-mlv.fr/~juge/javadoc-17/api/index.html.
Les seuls documents électroniques autorisés sont les supports de cours à l'url http://igm.univ-mlv.fr/~forax/ens/java-avance/cours/pdf/.

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.

Vous écrirez toutes les classes de ce TP noté dans un package nommé fr.uge.fs. Vous devez tester toutes les méthodes demandées et vous écrirez tous vos tests dans la classe fr.uge.fs.main.Main d'un sous-package.
Attention, il est très important de respecter les noms des paquetages, des classes, des champs et des méthodes que l'on vous demande : une partie de la correction est automatique.

Exercice 1 - Gestion de fichiers en mémoire

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).

  1. 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.

  2. 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.

  3. 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 !

  4. 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).

  5. 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.

  6. 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 !

  7. 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]
        

  8. 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]