CodeGym/Blog Java/Random-FR/Fichiers Java, Chemin
Auteur
Andrey Gorkovenko
Frontend Engineer at NFON AG

Fichiers Java, Chemin

Publié dans le groupe Random-FR
membres
Salut! Aujourd'hui, nous allons parler de l'utilisation de fichiers et de répertoires. Vous savez déjà comment gérer le contenu des fichiers : nous avons consacré de nombreuses leçons à cela :) Je pense qu'il vous est facile de vous souvenir de quelques classes utilisées à ces fins. Dans la leçon d'aujourd'hui, nous parlerons spécifiquement de la gestion des fichiers : créer, renommer, etc. Avant Java 7, toutes ces opérations étaient effectuées à l'aide de la classe File . Vous pouvez lire à ce sujet ici . Mais dans Java 7, les créateurs du langage ont décidé de changer notre façon de travailler avec les fichiers et les répertoires. Cela s'est produit parce que la classe File présentait plusieurs inconvénients. Par exemple, il n'avait pas la méthode copy() , qui vous permettrait de copier un fichier d'un emplacement à un autre (une capacité apparemment essentielle). De plus, leLa classe File avait plusieurs méthodes qui renvoyaient des valeurs booléennes . Lorsqu'il y a une erreur, une telle méthode renvoie false. Il ne lève pas d'exception, ce qui rend très difficile l'identification des erreurs et le diagnostic de leurs causes. A la place de l'unique classe File , 3 classes sont apparues : Paths , Path et Files . Eh bien, pour être précis, Path est une interface, pas une classe. Voyons en quoi ils diffèrent les uns des autres et pourquoi nous avons besoin de chacun d'eux. Commençons par le plus simple : Paths .

Chemins

Paths est une classe très simple avec une seule méthode statique : get() . Il a été créé uniquement pour obtenir un objet Path à partir de la chaîne ou de l'URI transmis. Il n'a pas d'autre fonctionnalité. En voici un exemple au travail :
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {

   public static void main(String[] args) {

       Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
   }
}
Ce n'est pas la classe la plus complexe, n'est-ce pas ? :) Eh bien, nous avons aussi ce type de chemin . Découvrons ce qu'est Path et pourquoi il est nécessaire :)

Chemin

Path , dans l'ensemble, est un analogue repensé de la classe File . Il est beaucoup plus facile de travailler avec que File . Tout d'abord , de nombreuses méthodes utilitaires (statiques) ont été supprimées et déplacées vers la classe Files . Deuxièmement , l'ordre a été imposé sur les valeurs de retour des méthodes de l' interface Path . Dans la classe File , les méthodes renvoyaient soit un String , soit un boolean , soit un File . Ce n'était pas facile à comprendre. Par exemple, il y avait une méthode getParent() qui renvoyait une chaîne représentant le chemin parent du fichier courant. Mais il y avait aussi ungetParentFile() , qui retourne la même chose mais sous la forme d'un objet File ! C'est clairement redondant. Par conséquent, dans l'interface Path , la méthode getParent() et d'autres méthodes pour travailler avec des fichiers renvoient simplement un objet Path . Pas de tas d'options - tout est facile et simple. Quelles sont certaines des méthodes utiles de Path ? En voici quelques-uns et des exemples de leur fonctionnement :
  • getFileName() : renvoie le nom du fichier à partir du chemin ;

  • getParent() : renvoie le répertoire "parent" du chemin courant (c'est-à-dire le répertoire situé immédiatement au-dessus dans l'arborescence des répertoires) ;

  • getRoot() : renvoie le répertoire "racine", c'est-à-dire le répertoire en haut de l'arborescence des répertoires ;

  • startsWith() , endsWith() : vérifie si le chemin commence/se termine par le chemin passé :

    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
    
           Path fileName = testFilePath.getFileName();
           System.out.println(fileName);
    
           Path parent = testFilePath.getParent();
           System.out.println(parent);
    
           Path root = testFilePath.getRoot();
           System.out.println(root);
    
           boolean endWithTxt = testFilePath.endsWith("Desktop\\testFile.txt");
           System.out.println(endWithTxt);
    
           boolean startsWithLalala = testFilePath.startsWith("lalalala");
           System.out.println(startsWithLalala);
       }
    }

    Sortie console :

    testFile.txt
    C:\Users\Username\Desktop
    C:\
    true
    false

    Faites attention au fonctionnement de la méthode endsWith() . Il vérifie si le chemin actuel se termine par le chemin transmis . Plus précisément, s'il se trouve dans le chemin , et non dans la chaîne transmise .

    Comparez les résultats de ces deux appels :

    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
    
           System.out.println(testFilePath.endsWith("estFile.txt"));
           System.out.println(testFilePath.endsWith("Desktop\\testFile.txt"));
       }
    }

    Sortie console :

    false
    true

    La méthode endsWith() doit recevoir un chemin authentique, pas seulement un ensemble de caractères : sinon, le résultat sera toujours faux, même si le chemin actuel se termine réellement par cette séquence de caractères (comme c'est le cas avec "estFile.txt " dans l'exemple ci-dessus).

    De plus, Path dispose d'un groupe de méthodes qui simplifient le travail avec les chemins absolus (complets) et relatifs .

Regardons ces méthodes :
  • boolean isAbsolute() renvoie vrai si le chemin courant est absolu :

    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
    
           System.out.println(testFilePath.isAbsolute());
       }
    }

    Sortie console :

    true
  • Path normalize() : "normalise" le chemin courant, en supprimant les éléments inutiles. Vous savez peut-être que dans les systèmes d'exploitation populaires, les symboles "." (répertoire courant) et ".." (répertoire parent) sont souvent utilisés pour désigner les chemins. Par exemple, " ./Pictures/dog.jpg " signifie que le répertoire courant a un dossier " Pictures ", qui à son tour contient un fichier " dog.jpg ".

    Regardez ici. Si un chemin utilisant "." ou ".." apparaît dans votre programme, la méthode normalize() les supprimera et produira un chemin qui ne les contiendra pas :

    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
    
           Path path5 = Paths.get("C:\\Users\\Java\\.\\examples");
    
           System.out.println(path5.normalize());
    
           Path path6 = Paths.get("C:\\Users\\Java\\..\\examples");
           System.out.println(path6.normalize());
       }
    }

    Sortie console :

    C:\Users\Java\examples
    C:\Users\examples
  • Path relativize() : calcule le chemin relatif entre le chemin courant et le chemin passé.

    Par exemple:

    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath1 = Paths.get("C:\\Users\\Users\\Users\\Users");
           Path testFilePath2 = Paths.get("C:\\Users\\Users\\Users\\Users\\Username\\Desktop\\testFile.txt");
    
           System.out.println(testFilePath1.relativize(testFilePath2));
       }
    }

    Sortie console :

    Username\Desktop\testFile.txt

La liste complète des méthodes Path est assez longue. Vous pouvez tous les trouver dans la documentation Oracle . Passons maintenant à l'examen de Files .

Des dossiers

Files est une classe utilitaire qui contient les méthodes statiques extraites de la classe File . Files est comparable à Arrays ou Collections . La différence est qu'il fonctionne avec des fichiers, pas avec des tableaux ou des collections :) Il se concentre sur la gestion des fichiers et des répertoires. En utilisant les méthodes statiques de la classe Files , nous pouvons créer, supprimer et déplacer des fichiers et des répertoires. Ces opérations sont effectuées à l'aide desméthodes createFile() (pour les répertoires, createDirectory() ), move() et delete() . Voici comment les utiliser :
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

public class Main {

   public static void main(String[] args) throws IOException {

       // Create a file
       Path testFile1 = Files.createFile(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt"));
       System.out.println("Was the file created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       // Create a directory
       Path testDirectory = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory"));
       System.out.println("Was the directory created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory")));

       // Move the file from the desktop to the testDirectory directory. When you move a folder, you need to indicate its name in the folder!
       testFile1 = Files.move(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt"), REPLACE_EXISTING);

       System.out.println("Did our file remain on the desktop?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       System.out.println("Has our file been moved to testDirectory?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt")));

       // Delete a file
       Files.delete(testFile1);
       System.out.println("Does the file still exist?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt")));
   }
}
Ici, nous créons d'abord un fichier ( méthode Files.createFile() ) sur le bureau. Ensuite, nous créons un dossier au même emplacement ( méthode Files.createDirectory() ). Après cela, nous déplaçons le fichier ( méthode Files.move() ) du bureau vers ce nouveau dossier, et enfin nous supprimons le fichier ( méthode Files.delete() ). Sortie console :
Was the file created successfully?
true
Was the directory created successfully?
true
Did our file remain on the desktop?
false
Has our file been moved to testDirectory?
true
Does the file still exist?
false
Note:comme les méthodes de l' Pathinterface, de nombreuses méthodes de la Filesclasse renvoient unPath objet. La plupart des méthodes de la Filesclasse prennent également Pathdes objets en entrée. Ici, la Paths.get()méthode sera votre fidèle assistante, faites-en bon usage. Quoi d'autre est intéressant Files? FileCe qui manquait vraiment à l'ancienne classe, c'est une copy()méthode ! Nous en avons parlé au début de cette leçon. Il est maintenant temps de le rencontrer!
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

public class Main {

   public static void main(String[] args) throws IOException {

       // Create a file
       Path testFile1 = Files.createFile(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt"));
       System.out.println("Was the file created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       // Create a directory
       Path testDirectory2 = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2"));
       System.out.println("Was the directory created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2")));

       // Copy the file from the desktop to the testDirectory2 directory.
       testFile1 = Files.copy(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt"), REPLACE_EXISTING);

       System.out.println("Did our file remain on the desktop?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       System.out.println("Was our file copied to testDirectory?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt")));
   }
}
Sortie console :
Was the file created successfully?
true
Was the directory created successfully?
true
Did our file remain on the desktop?
true
Was our file copied to testDirectory?
true
Vous savez maintenant comment copier des fichiers par programmation ! :) Bien sûr, la Filesclasse vous permet non seulement de gérer un fichier lui-même, mais aussi de travailler avec son contenu. Il a la write()méthode pour écrire des données dans un fichier, et les 3 méthodes pour lire les données : read(), readAllBytes(), et readAllLines() Nous nous attarderons en détail sur la dernière. Pourquoi celui-là ? Parce qu'il a un type de retour très intéressant : List<String>! Autrement dit, il nous renvoie une liste de toutes les lignes du fichier. Bien sûr, cela rend très pratique le travail avec le contenu du fichier, car le fichier entier, ligne par ligne, peut, par exemple, être affiché sur la console à l'aide d'une boucle ordinaire for:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;

public class Main {

   public static void main(String[] args) throws IOException {

       List<String> lines = Files.readAllLines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"), UTF_8);

       for (String s: lines) {
           System.out.println(s);
       }
   }
}
Sortie console :
I still recall the wondrous moment:
When you appeared before my sight,
As though a brief and fleeting omen,
Pure phantom in enchanting light.
Hyper pratique ! :) Cette capacité est apparue dans Java 7. L' API Stream est apparue dans Java 8. Elle ajoute des éléments de programmation fonctionnelle à Java. Y compris des capacités de gestion de fichiers plus riches. Imaginons que nous ayons la tâche suivante : trouver toutes les lignes qui commencent par le mot "As", les convertir en MAJUSCULES et les afficher sur la console. À quoi ressemblerait une solution utilisant la Filesclasse dans Java 7 ? Quelque chose comme ça:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;

public class Main {

   public static void main(String[] args) throws IOException {

       List<String> lines = Files.readAllLines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"), UTF_8);

       List<String> result = new ArrayList<>();

       for (String s: lines) {
           if (s.startsWith("As")) {
               String upper = s.toUpperCase();
               result.add(upper);
           }
       }

       for (String s: result) {
           System.out.println(s);
       }
   }
}
Sortie console :
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
Mission accomplie, mais ne pensez-vous pas que pour une tâche aussi simple notre code s'est avéré un peu... verbeux ? En utilisant l'API Stream de Java 8, la solution semble beaucoup plus élégante :
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {

   public static void main(String[] args) throws IOException {

       Stream<String> stream = Files.lines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"));

       List<String> result  = stream
               .filter(line -> line.startsWith("As"))
               .map(String::toUpperCase)
               .collect(Collectors.toList());
       result.forEach(System.out::println);
   }
}
Nous avons obtenu le même résultat, mais avec beaucoup moins de code ! De plus, personne ne peut dire que nous avons perdu la "lisibilité". Je pense que vous pouvez facilement commenter ce que fait ce code, même sans être familier avec l'API Stream. En bref, un flux est une séquence d'éléments sur lesquels vous pouvez effectuer diverses opérations. Nous obtenons un objet Stream de la Files.lines()méthode, puis lui appliquons 3 fonctions :
  1. Nous utilisons la filter()méthode pour sélectionner uniquement les lignes du fichier qui commencent par "As".

  2. Nous parcourons toutes les lignes sélectionnées à l'aide de la map()méthode et convertissons chacune d'elles en MAJUSCULES.

  3. Nous utilisons la collect()méthode pour rassembler toutes les lignes reçues dans un fichier List.

Nous obtenons le même résultat :
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
Revenons maintenant à notre pain quotidien, c'est-à-dire aux fichiers :) La dernière capacité que nous allons considérer aujourd'hui consiste à parcourir une arborescence de fichiers . Dans les systèmes d'exploitation modernes, la structure des fichiers ressemble le plus souvent à une arborescence : elle a une racine et il y a des branches, qui peuvent avoir d'autres branches, etc. La racine et les branches sont des répertoires. Par exemple, le répertoire " С:// " peut être la racine. Il comprend deux branches : " C://Downloads " et " C://Users ". Chacune de ces branches a deux branches : " C://Downloads/Pictures ", " C://Downloads/Video ", " C://Users/JohnSmith ", " C://Users/Pudge2005". Et ces branches ont à leur tour d'autres branches, etc. et c'est pourquoi nous appelons cela un arbre. Sous Linux, la structure est similaire, mais le répertoire / est la racine. Imaginons maintenant que nous devions commencer par le répertoireFichiers, Chemin - 2 racine , parcourez tous ses dossiers et sous-dossiers et trouvez les fichiers qui ont un contenu particulier. Nous allons rechercher les fichiers qui contiennent la ligne "C'est le fichier dont nous avons besoin !" Nous allons prendre le dossier "testFolder", qui est sur le bureau, en tant que répertoire racine. Voici son contenu : Fichiers, Chemin - 3Les dossiers level1-a et level1-b contiennent également des dossiers : Fichiers, Chemin - 4Fichiers, Chemin - 5Il n'y a pas de dossiers dans ces "dossiers de second niveau", uniquement des fichiers individuels : Fichiers, Chemin - 6Fichiers, Chemin - 7Les 3 fichiers avec le contenu dont nous avons besoin portent délibérément des noms explicatifs : FileWeNeed1.txt, FileWeNeed2.txt, FileWeNeed3.txt. Ce sont précisément les fichiers que nous devons trouver en utilisant Java. Comment faisons-nous cela? Une méthode très puissante pour parcourir une arborescence de fichiers vient à notre secours : Files.walkFileTree (). Voici ce que nous devons faire. Tout d'abord, nous avons besoin d'un FileVisitor. FileVisitorest une interface spéciale, dans laquelle les méthodes pour parcourir une arborescence de fichiers sont décrites. En particulier, c'est là que nous placerons la logique pour lire le contenu d'un fichier et vérifier s'il contient le texte dont nous avons besoin. Voici à quoi FileVisitorressemble notre:
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;

public class MyFileVisitor extends SimpleFileVisitor<Path> {

   @Override
   public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {

       List<String> lines = Files.readAllLines(file);
       for (String s: lines) {
           if (s.contains("This is the file we need")) {
               System.out.println("We found a file we need!");
               System.out.println(file.toAbsolutePath());
               break;
           }
       }

       return FileVisitResult.CONTINUE;
   }
}
Dans ce cas, notre classe hérite de SimpleFileVisitor. Il s'agit d'une classe qui implémente FileVisitor, dans laquelle nous devons remplacer une seule méthode : visitFile(). Ici, nous définissons ce qui doit être fait avec chaque fichier dans chaque répertoire. Si vous avez besoin d'une logique plus complexe pour parcourir la structure du fichier, vous devez écrire votre propre implémentation de FileVisitor. Vous auriez besoin d'implémenter 3 méthodes supplémentaires dans cette classe :
  • preVisitDirectory(): la logique à exécuter avant d'entrer dans un dossier ;

  • visitFileFailed(): la logique à exécuter si un fichier ne peut être visité (pas d'accès, ou pour d'autres raisons) ;

  • postVisitDirectory(): la logique à exécuter après avoir entré un dossier.

Nous n'avons pas besoin d'exécuter une telle logique, donc nous sommes d'accord avec SimpleFileVisitor. La logique à l'intérieur de la visitFile()méthode est assez simple : lisez toutes les lignes du fichier, vérifiez si elles contiennent le contenu dont nous avons besoin, et si c'est le cas, imprimez le chemin absolu sur la console. La seule ligne qui pourrait vous poser problème est celle-ci :
return FileVisitResult.CONTINUE;
En fait, c'est très simple. Ici, nous décrivons simplement ce que le programme doit faire une fois que le fichier a été visité et que toutes les opérations nécessaires ont été effectuées. Dans notre cas, nous voulons continuer à parcourir l'arbre, nous choisissons donc l' CONTINUEoption. Mais, alternativement, nous pourrions avoir un objectif différent : au lieu de rechercher tous les fichiers contenant "Ceci est le fichier dont nous avons besoin", recherchez un seul de ces fichiers . Après cela, le programme devrait se terminer. Dans ce cas, notre code aurait exactement la même apparence, mais au lieu de break, il y aurait :
return FileVisitResult.TERMINATE;
Eh bien, exécutons notre code et voyons si cela fonctionne.
import java.io.IOException;
import java.nio.file.*;

public class Main {

   public static void main(String[] args) throws IOException {

       Files.walkFileTree(Paths.get("C:\\Users\\Username\\Desktop\\testFolder"), new MyFileVisitor());
   }
}
Sortie console :
We found a file we need!
C:\Users\Username\Desktop\testFolder\FileWeNeed1.txt
We found a file we need!
C:\Users\Username\Desktop\testFolder\level1-a\level2-a-a\FileWeNeed2.txt
We found a file we need!
C:\Users\Username\Desktop\testFolder\level1-b\level2-b-b\FileWeNeed3.txt
Excellent! Ça a marché! :) Vous pouvez également accepter ce petit défi : remplacer SimpleFileVisitorpar un ordinaire FileVisitor, remplacer les 4 méthodes et proposer votre propre objectif pour le programme. Par exemple, vous pourriez écrire un programme qui journalise toutes ses actions : afficher le nom du fichier ou du dossier avant ou après les avoir saisis. C'est tout pour le moment. À bientôt! :)
Commentaires
  • Populaires
  • Nouveau
  • Anciennes
Tu dois être connecté(e) pour laisser un commentaire
Cette page ne comporte pas encore de commentaires