JavaRush /Blog Java /Random-FR /Fichiers Java, chemin

Fichiers Java, chemin

Publié dans le groupe Random-FR
Bonjour! Aujourd'hui, nous allons parler du travail avec des fichiers et des répertoires. Vous savez déjà comment gérer le contenu des fichiers : nous avons eu beaucoup de cours consacrés à cela :) Je pense que vous vous souvenez facilement de plusieurs cours nécessaires à ces fins. Dans la conférence d'aujourd'hui, nous parlerons spécifiquement de la gestion des fichiers - création, renommage, etc. Avant Java 7, toutes ces opérations étaient effectuées à l'aide du fichier File. Vous pouvez lire son travail ici . Mais dans Java 7, les créateurs du langage ont décidé de changer leur façon de travailler avec les fichiers et les répertoires. Cela était dû au fait que la classe Fileprésentait un certain nombre d'inconvénients. Par exemple, il ne disposait pas d'une méthode copy()qui vous permettrait de copier un fichier d'un emplacement à un autre (une fonctionnalité apparemment clairement nécessaire). De plus, la classe Filedisposait de nombreuses méthodes renvoyant booleandes valeurs. Si une erreur se produit, une telle méthode renvoie false plutôt que de lever une exception, ce qui rend le diagnostic des erreurs et la détermination de leurs causes très difficiles. Au lieu d'une seule classe, Filejusqu'à 3 classes sont apparues : Paths, Pathet Files. Eh bien, pour être précis, Pathil s'agit d'une interface, pas d'une classe. Voyons en quoi ils diffèrent les uns des autres et pourquoi chacun d'eux est nécessaire. Commençons par la chose la plus simple : Paths.

Chemins

Pathsest une classe très simple avec une seule méthode statique get(). Il a été créé uniquement pour obtenir un objet de type à partir de la chaîne ou de l'URI transmis Path. Il n'a aucune autre fonctionnalité. Voici un exemple de son 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 le cours le plus difficile, non ? :) Eh bien, puisque nous avons un objet de type Path, voyons ce que c'est Pathet pourquoi il est nécessaire :)

Chemin

Path, dans l’ensemble, est un analogue repensé du File. Il est beaucoup plus facile de travailler avec qu'avec File. Premièrement , de nombreuses méthodes utilitaires (statiques) en ont été supprimées et déplacées vers la classe Files. Deuxièmement , Pathles valeurs de retour des méthodes ont été ordonnées. Dans la classe, Fileles méthodes renvoyaient ceci String, cela boolean, cela File- ce n'était pas facile à comprendre. Par exemple, il existait une méthode getParent()qui renvoyait le chemin parent du fichier actuel sous forme de chaîne. Mais en même temps il y avait une méthode getParentFile()qui retournait la même chose, mais sous la forme d'un objet File! C'est clairement redondant. Par conséquent, dans l'interface, Pathla méthode getParent()et d'autres méthodes permettant de travailler avec des fichiers renvoient simplement un objet Path. Pas beaucoup d'options - tout est facile et simple. De quelles méthodes utiles dispose-t-il Path? En voici quelques-uns et des exemples de leur travail :
  • getFileName()— renvoie le nom du fichier à partir du chemin ;

  • getParent()— renvoie le répertoire « parent » par rapport au chemin actuel (c'est-à-dire le répertoire qui se trouve plus haut dans l'arborescence des répertoires) ;

  • getRoot()— renvoie le répertoire « racine » ; c'est-à-dire celui qui se trouve en haut de l'arborescence des répertoires ;

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

    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 de la console :

    testFile.txt
    C:\Utilisateurs\Nom d'utilisateur\Desktop
    C:\
    vrai
    faux

    Faites attention au fonctionnement de la méthode endsWith(). Il vérifie si le chemin actuel se termine par le chemin passé . C'est sur le chemin , et non sur l'ensemble des personnages .

    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 de la console :

    faux
    vrai

    Vous devez transmettre le chemin complet à la méthode endsWith(), et pas seulement un ensemble de caractères : sinon le résultat sera toujours false , même si le chemin actuel se termine en réalité par une telle séquence de caractères (comme dans le cas de « estFile.txt " dans l'exemple ci-dessus).

    De plus, il Pathexiste un groupe de méthodes qui simplifient le travail avec des chemins absolus (complets) et relatifs .

Examinons ces méthodes :
  • boolean isAbsolute()— renvoie vrai si le chemin actuel 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 de la console :

    vrai

  • Path normalize()— « normalise » le chemin actuel, en supprimant les éléments inutiles. Vous savez peut-être que les systèmes d'exploitation populaires utilisent souvent les caractères « . » pour désigner les chemins. (« répertoire courant ») et « .. » (répertoire parent). Par exemple : « ./Pictures/dog.jpg » signifie que dans le répertoire dans lequel nous nous trouvons actuellement, il y a un dossier Images, et dedans il y a un fichier « dog.jpg »

    Alors voilà. Si votre programme a un chemin qui utilise « ». ou « .. », la méthode normalize()les supprimera et obtiendra 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 de la console :

    C:\Utilisateurs\Java\exemples
    C:\Utilisateurs\exemples

  • Path relativize()— calcule le chemin relatif entre le chemin actuel 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 de la console :

    Nom d'utilisateur\Bureau\testFile.txt

La liste complète des méthodes Pathest assez longue. Vous pouvez tous les trouver dans la documentation Oracle . Nous allons passer à l'examen Files.

Des dossiers

Files- il s'agit d'une classe utilitaire dans laquelle les méthodes statiques de la classe ont été déplacées File. Files- c'est à peu près la même chose que Arraysou Collections, sauf qu'il fonctionne avec des fichiers, et non avec des tableaux et des collections :) Il se concentre sur la gestion des fichiers et des répertoires. En utilisant des méthodes statiques Files, nous pouvons créer, supprimer et déplacer des fichiers et des répertoires. Pour ces opérations, les méthodes sont utilisées 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 {

       //file creation
       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 directory
       Path testDirectory = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory"));
       System.out.println("Was the directory successfully created?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory")));

       //move file from desktop to testDirectory. You need to move with the name of the file in the folder!
       testFile1 = Files.move(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt"), REPLACE_EXISTING);

       System.out.println("Is our file left 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")));

       //remove 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, puis y créons un dossier (méthode Files.createDirectory()). Après cela, nous déplaçons le fichier (méthode Files.move()) du bureau vers ce nouveau dossier, et à la fin nous supprimons le fichier (méthode Files.delete()). Résultat de la console : le fichier a-t-il été créé avec succès ? true Le répertoire a-t-il été créé avec succès ? true Notre fichier est-il toujours sur le bureau ? false Notre fichier a-t-il été déplacé vers testDirectory ? true Le fichier existe-t-il toujours ? FAUX Faites attention:Tout comme les méthodes d'interface Path, de nombreuses méthodes Filesrenvoient un objetPath . La plupart des méthodes de classe Filesacceptent également Path. Ici, une méthode deviendra votre fidèle assistant Paths.get()- utilisez-la activement. Qu'est-ce qui est intéressant d'autre Files? Ce qui manquait vraiment à l’ancienne classe, c’était la Fileméthode copy()! . Nous avons parlé de lui au début de la conférence, c'est le moment 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 {

       //file creation
       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 directory
       Path testDirectory2 = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2"));
       System.out.println("Was the directory successfully created?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2")));

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

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

       System.out.println("Has our file been copied to testDirectory?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt")));
   }
}
Résultat de la console : le fichier a-t-il été créé avec succès ? true Le répertoire a-t-il été créé avec succès ? true Notre fichier est-il toujours sur le bureau ? true Notre fichier a-t-il été copié dans testDirectory ? true Vous pouvez désormais copier des fichiers par programme ! :) Mais la classe Filespermet non seulement de gérer les fichiers eux-mêmes, mais aussi de travailler avec leur contenu. Pour écrire des données dans un fichier, il dispose d'une méthode write(), et pour la lecture - jusqu'à 3 :, read()et readAllBytes()nous readAllLines() nous attarderons sur cette dernière en détail. Pourquoi dessus ? Parce qu'il a un type de retour très intéressant - List<String>! Autrement dit, il nous renvoie une liste de lignes du fichier. Bien sûr, cela rend le travail avec le contenu très pratique, car le fichier entier, ligne par ligne, peut, par exemple, être sorti sur la console dans une boucle régulière 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 : Je me souviens d'un moment merveilleux : Tu es apparue devant moi, Comme une vision fugace, Comme un génie de pure beauté. Très confortablement ! :) Cette fonctionnalité est apparue dans Java 7. Dans Java 8, l'API Stream est apparue , qui a ajouté certains éléments de programmation fonctionnelle à Java. Y compris des fonctionnalités plus riches pour travailler avec des fichiers. Imaginez que nous ayons une tâche : trouver toutes les lignes d'un fichier qui commencent par le mot « Comment », les convertir en MAJUSCULES et les afficher sur la console. À quoi ressemblerait une solution utilisant une classe Filesen 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("How")) {
               String upper = s.toUpperCase();
               result.add(upper);
           }
       }

       for (String s: result) {
           System.out.println(s);
       }
   }
}
Résultat de la console : COMME UNE VISION À JEÛNE, COMME UN GÉNIE DE PURE BEAUTÉ. Il semble que nous l'ayons fait, 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 Java 8 Stream, 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("How"))
               .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 ! Par ailleurs, on ne peut pas dire que nous ayons perdu en « lisibilité ». Je pense que vous pouvez facilement commenter ce que fait ce code, même si vous n'êtes pas familier avec l'API Stream. Mais en bref, un Stream est une séquence d’éléments sur lesquels vous pouvez réaliser différentes fonctions. Nous récupérons l'objet Stream de la méthode Files.lines()puis lui appliquons 3 fonctions :
  1. En utilisant la méthode, filter()nous sélectionnons uniquement les lignes du fichier qui commencent par « Comment ».

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

  3. Nous combinons toutes les lignes résultantes en Listutilisant le collect().

A la sortie on obtient le même résultat : COMME UNE VISION À JEÛNE, COMME UN GÉNIE DE PURE BEAUTÉ. Si vous souhaitez en savoir plus sur les capacités de cette bibliothèque, nous vous recommandons de lire cet article . Nous reviendrons à nos moutons, c'est-à-dire aux fichiers :) La dernière possibilité que nous envisagerons aujourd'hui est de parcourir l'arborescence des fichiers . La structure des fichiers dans les systèmes d'exploitation modernes prend le plus souvent la forme d'un arbre : elle a une racine et il existe des branches dont d'autres branches peuvent être séparées, etc. Les répertoires jouent le rôle de racine et de branches. Par exemple, le répertoire « C:// » peut faire office de racine . Deux branches en dérivent : « C://Downloads » et « C://Users ». De chacune de ces branches, il y a 2 branches supplémentaires : « C://Downloads/Pictures », « C://Downloads/Video », « C://Users/JohnSmith », « C://Users/Pudge2005 » . D'autres branches partent de ces branches, etc. - c'est ainsi que se révèle un arbre. Sous Linux, cela a à peu près la même apparence, seulement là, le répertoire fait office de racine / Fichiers, chemin - 2 Imaginez maintenant que nous avons une tâche : connaissant le répertoire racine, nous devons le parcourir, regarder dans les dossiers de tous les niveaux et y trouver des fichiers avec le contenu nous avons besoin. Nous rechercherons les fichiers contenant la ligne « C'est le fichier dont nous avons besoin ! » Notre répertoire racine sera le dossier « testFolder », qui se trouve sur le bureau. À l'intérieur, il contient le contenu suivant : Fichiers, chemin - 3Dans les dossiers niveau1-a et niveau1-b se trouvent également des dossiers : Fichiers, chemin - 4Fichiers, chemin - 5À l'intérieur de ces « dossiers de deuxième niveau », il n'y a plus de dossiers, seulement des fichiers individuels : Fichiers, chemin - 6Fichiers, chemin - 7Nous désignerons spécialement 3 fichiers avec le contenu que nous besoin avec des noms clairs - FileWeNeed1.txt , FileWeNeed2.txt, FileWeNeed3.txt Ce sont ceux que nous devons trouver par contenu en utilisant Java. Comment peut-on le faire? Une méthode très puissante pour parcourir une arborescence de fichiers vient à la rescousse - Files.walkFileTree(). Voici ce que nous devons faire. Premièrement, nous avons besoin FileVisitor. FileVisitorest une interface spéciale qui décrit toutes les méthodes permettant de parcourir l'arborescence des fichiers. Concrètement, nous y mettrons une logique pour lire le contenu du fichier et vérifier s'il contient le texte dont nous avons besoin. Voici à quoi ressemblera le nôtre FileVisitor:
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("Required file found!");
               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 vous ne devez remplacer qu'une seule méthode : visitFile(). Nous décrivons ici ce qui doit être fait avec chaque fichier dans chaque répertoire. Si vous avez besoin d'une logique de traversée plus complexe, vous devez écrire votre propre implémentation FileVisitor. Là, vous devrez implémenter 3 méthodes supplémentaires :
  • preVisitDirectory()— logique qui doit être exécutée avant d'entrer dans le dossier ;

  • visitFileFailed()— que faire si la saisie du fichier est impossible (pas d'accès ou autres raisons) ;

  • postVisitDirectory()— la logique qui doit être exécutée après être entré dans le dossier.

Nous n’avons pas une telle logique, donc cela nous suffit SimpleFileVisitor. La logique à l'intérieur de la méthode visitFile()est assez simple : lire toutes les lignes du fichier, vérifier si elles contiennent le contenu dont nous avons besoin et si c'est le cas, imprimer le chemin absolu vers la console. La seule ligne qui pourrait vous poser problème est celle-ci :
return FileVisitResult.CONTINUE;
En fait, tout est simple. Ici, nous décrivons simplement ce que le programme doit faire une fois que le fichier a été saisi et que toutes les opérations nécessaires ont été effectuées. Dans notre cas, nous devons continuer à parcourir l’arbre, nous choisissons donc l’option CONTINUE. Mais nous pourrions, par exemple, avoir une autre tâche : trouver non pas tous les fichiers contenant « Ceci est le fichier dont nous avons besoin », mais un seul de ces fichiers . Après cela, le programme doit être terminé. Dans ce cas, notre code aurait exactement le même aspect, mais au lieu de break ; serait:
return FileVisitResult.TERMINATE;
Eh bien, exécutons notre code et voyons s'il 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());
   }
}
Résultat de la console :  le fichier requis a été trouvé ! C:\Users\Username\Desktop\testFolder\FileWeNeed1.txt Le fichier requis a été trouvé ! C:\Users\Username\Desktop\testFolder\level1-a\level2-aa\FileWeNeed2.txt Le fichier requis a été trouvé ! C:\Users\Username\Desktop\testFolder\level1-b\level2-bb\FileWeNeed3.txt Super, nous l'avons fait ! :) Si vous souhaitez en savoir plus walkFileTree(), je vous recommande cet article . Vous pouvez également effectuer une petite tâche - la remplacer SimpleFileVisitorpar une tâche régulière FileVisitor, mettre en œuvre les 4 méthodes et proposer un objectif pour ce programme. Par exemple, vous pouvez écrire un programme qui enregistrera toutes vos actions : afficher le nom d'un fichier ou d'un dossier dans la console avant/après les avoir saisis. C'est tout - à plus tard ! :)
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION