Guide de NIO2 FileVisitor

Un guide pour NIO2 FileVisitor

1. Vue d'ensemble

Dans cet article, nous allons explorer une fonctionnalité intéressante de NIO2 - l'interfaceFileVisitor.

Tous les systèmes d'exploitation et plusieurs applications tierces disposent d'une fonction de recherche de fichier dans laquelle un utilisateur définit les critères de recherche.

Cette interface est ce dont nous avons besoin pour implémenter une telle fonctionnalité dans une application Java. Si vous avez besoin de rechercher tous les fichiers.mp3, de trouver et de supprimer les fichiers.class ou de trouver tous les fichiers qui n’ont pas été consultés le mois dernier, cette interface est ce dont vous avez besoin.

Toutes les classes dont nous avons besoin pour implémenter cette fonctionnalité sont regroupées dans un seul package:

import java.nio.file.*;

2. Fonctionnement deFileVisitor

Avec l'interfaceFileVisitor, vous pouvez parcourir l'arborescence des fichiers à n'importe quelle profondeur et effectuer n'importe quelle action sur les fichiers ou répertoires trouvés sur n'importe quelle branche.

Une implémentation typique de l'interfaceFileVisitor ressemble à ceci:

public class FileVisitorImpl implements FileVisitor {

    @Override
    public FileVisitResult preVisitDirectory(
      Path dir, BasicFileAttributes attrs) {
        return null;
    }

    @Override
    public FileVisitResult visitFile(
      Path file, BasicFileAttributes attrs) {
        return null;
    }

    @Override
    public FileVisitResult visitFileFailed(
      Path file, IOException exc) {
        return null;
    }

    @Override
    public FileVisitResult postVisitDirectory(
      Path dir, IOException exc) {
        return null;
    }
}

Les quatre méthodes d'interface nous permettent de spécifier le comportement requis aux points clés du processus de parcours: avant l'accès à un répertoire, lorsqu'un fichier est visité, ou en cas d'échec et après l'accès à un répertoire, respectivement.

La valeur de retour à chaque étape est de typeFileVisitResult et contrôle le flux de la traversée. Peut-être souhaitez-vous parcourir l’arborescence de fichiers à la recherche d’un répertoire particulier et mettre fin au processus dès qu’il est trouvé ou vous souhaitez ignorer des répertoires ou des fichiers spécifiques.

FileVisitResult est une énumération de quatre valeurs de retour possibles pour les méthodes d'interfaceFileVisitor:

  • FileVisitResult.CONTINUE - indique que la traversée de l'arborescence de fichiers doit se poursuivre après la sortie de la méthode qui la renvoie

  • FileVisitResult.TERMINATE - arrête la traversée de l'arborescence des fichiers et aucun autre répertoire ou fichier n'est visité

  • FileVisitResult.SKIP_SUBTREE - ce résultat n'a de sens que lorsqu'il est renvoyé par l'APIpreVisitDirectory, ailleurs, il fonctionne commeCONTINUE. Il indique que le répertoire en cours et tous ses sous-répertoires doivent être ignorés

  • FileVisitResult.SKIP_SIBLINGS - indique que la traversée doit se poursuivre sans visiter les frères du fichier ou du répertoire courant. S'il est appelé dans la phasepreVisitDirectory, alors même le répertoire courant est ignoré et lepostVisitDirectory n'est pas appelé

Enfin, il doit y avoir un moyen de déclencher le processus de parcours, peut-être lorsque l'utilisateur clique sur le boutonsearch depuis une interface utilisateur graphique après avoir défini les critères de recherche. C'est la partie la plus simple.

Il suffit d'appeler l'API statiquewalkFileTree de la classeFiles et de lui passer une instance de la classePath qui représente le point de départ de la traversée puis une instance de notreFileVisitor:

Path startingDir = Paths.get("pathToDir");
FileVisitorImpl visitor = new FileVisitorImpl();
Files.walkFileTree(startingDir, visitor);

3. Exemple de recherche de fichier

Dans cette section, nous allons implémenter une application de recherche de fichiers en utilisant l'interfaceFileVisitor. Nous voulons permettre à l'utilisateur de spécifier le nom de fichier complet avec extension et un répertoire de départ dans lequel regarder.

Lorsque nous trouvons le fichier, nous imprimons un message de réussite à l'écran et, lorsque l'arborescence de fichiers entière est recherchée sans que le fichier soit trouvé, nous imprimons également un message d'échec approprié.

3.1. La classe principale

Nous appellerons cette classeFileSearchExample.java:

public class FileSearchExample implements FileVisitor {
    private String fileName;
    private Path startDir;

    // standard constructors
}

Nous n'avons pas encore implémenté les méthodes d'interface. Notez que nous avons créé un constructeur qui prend le nom du fichier à rechercher et le chemin à partir duquel effectuer la recherche. Nous utiliserons uniquement le chemin de départ comme cas de base pour conclure que le fichier n'a pas été trouvé.

Dans les sous-sections suivantes, nous allons implémenter chaque méthode d'interface et discuter de son rôle dans cet exemple d'application particulier.

3.2. L'APIpreVisitDirectory

Commençons par implémenter l'APIpreVisitDirectory:

@Override
public FileVisitResult preVisitDirectory(
  Path dir, BasicFileAttributes attrs) {
    return CONTINUE;
}

Comme nous l'avons dit précédemment, cette API est appelée à chaque fois que le processus rencontre un nouveau répertoire dans l'arborescence. Sa valeur de retour détermine ce qui va se passer ensuite en fonction de ce que nous décidons. C’est à ce stade que nous ignorerions des répertoires spécifiques et les éliminerions de l’échantillon de recherche.

Choisissons de ne discriminer aucun répertoire et cherchons simplement dans chacun d’entre eux.

3.3. L'APIvisitFile

Ensuite, nous allons implémenter l'APIvisitFile. C'est là que se passe l'action principale. Cette API s'appelle chaque fois qu'un fichier est rencontré. Nous en profitons pour vérifier les attributs du fichier et comparer avec nos critères et renvoyer un résultat approprié:

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
    String fileName = file.getFileName().toString();
    if (FILE_NAME.equals(fileName)) {
        System.out.println("File found: " + file.toString());
        return TERMINATE;
    }
    return CONTINUE;
}

Dans notre cas, nous vérifions uniquement le nom du fichier visité pour savoir s'il s'agit de celui que l'utilisateur recherche. Si les noms correspondent, nous imprimons un message de réussite et mettons fin au processus. Cependant, il y a tant à faire ici, surtout après avoir lu le

Cependant, il y a tellement de choses à faire ici, surtout après avoir lu la sectionFile Attributes. Vous pouvez vérifier l'heure de création, l'heure de la dernière modification ou les dernières heures d'accès ou plusieurs attributs disponibles dans le paramètreattrs et décider en conséquence.

3.4. L'APIvisitFileFailed

Ensuite, nous allons implémenter l'APIvisitFileFailed. Cette API est appelée lorsqu'un fichier spécifique n'est pas accessible à la machine virtuelle Java. Peut-être a-t-il été verrouillé par une autre application ou pourrait-il s'agir simplement d'un problème de permission:

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
    System.out.println("Failed to access file: " + file.toString());
    return CONTINUE;
}

Nous enregistrons simplement un message d'échec et continuons avec la traversée du reste de l'arborescence. Dans une application graphique, vous pouvez choisir de demander à l'utilisateur s'il souhaite continuer ou non à l'aide d'une boîte de dialogue ou simplement consigner le message quelque part et compiler un rapport pour une utilisation ultérieure.

3.5. L'APIpostVisitDirectory

Enfin, nous implémenterons l'APIpostVisitDirectory. Cette API est appelée à chaque fois qu'un répertoire est entièrement parcouru:

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc){
    boolean finishedSearch = Files.isSameFile(dir, START_DIR);
    if (finishedSearch) {
        System.out.println("File:" + FILE_NAME + " not found");
        return TERMINATE;
    }
    return CONTINUE;
}

Nous utilisons l'APIFiles.isSameFile pour vérifier si le répertoire qui vient d'être parcouru est le répertoire à partir duquel nous avons commencé la traversée. Si la valeur de retour esttrue, cela signifie que la recherche est terminée et que le fichier n'a pas été trouvé. Nous terminons donc le processus avec un message d'échec.

Cependant, si la valeur de retour estfalse, cela signifie que nous venons de finir de parcourir un sous-répertoire et qu'il y a toujours une probabilité de trouver le fichier dans un autre sous-répertoire. Nous continuons donc avec traversal.

Nous pouvons maintenant ajouter notre méthode principale pour exécuter l'applicationFileSearchExample:

public static void main(String[] args) {
    Path startingDir = Paths.get("C:/Users/user/Desktop");
    String fileToSearch = "hibernate-guide.txt"
    FileSearchExample crawler = new FileSearchExample(
      fileToSearch, startingDir);
    Files.walkFileTree(startingDir, crawler);
}

Vous pouvez jouer avec cet exemple en modifiant les valeurs des variablesstartingDir etfileToSearch. LorsquefileToSearch existe dansstartingDir ou dans l'un de ses sous-répertoires, vous obtiendrez un message de réussite, sinon un message d'échec.

4. Conclusion

Dans cet article, nous avons exploré certaines des fonctionnalités les moins couramment utilisées disponibles dans les API du système de fichiers Java 7 NIO.2, en particulier l'interfaceFileVisitor. Nous avons également réussi à créer une application de recherche de fichiers afin de démontrer ses fonctionnalités.

Le code source complet des exemples utilisés dans cet article est disponible dans leGithub project.