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 .
-
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
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' Path
interface, de nombreuses méthodes de la Files
classe renvoient unPath
objet. La plupart des méthodes de la Files
classe prennent également Path
des 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
? File
Ce 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 Files
classe 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 Files
classe 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 :
-
Nous utilisons la
filter()
méthode pour sélectionner uniquement les lignes du fichier qui commencent par "As". -
Nous parcourons toutes les lignes sélectionnées à l'aide de la
map()
méthode et convertissons chacune d'elles en MAJUSCULES. -
Nous utilisons la
collect()
méthode pour rassembler toutes les lignes reçues dans un fichierList
.
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épertoire 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 : Les dossiers level1-a et level1-b contiennent également des dossiers : Il n'y a pas de dossiers dans ces "dossiers de second niveau", uniquement des fichiers individuels : Les 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
. FileVisitor
est 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 FileVisitor
ressemble 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.
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' CONTINUE
option. 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 SimpleFileVisitor
par 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! :)
GO TO FULL VERSION