Ein Leitfaden für NIO2 FileVisitor

Eine Anleitung zu NIO2 FileVisitor

1. Überblick

In diesem Artikel werden wir eine interessante Funktion von NIO2 untersuchen - dieFileVisitor-Schnittstelle.

Alle Betriebssysteme und mehrere Anwendungen von Drittanbietern verfügen über eine Dateisuchfunktion, in der ein Benutzer Suchkriterien definiert.

Diese Schnittstelle benötigen wir, um eine solche Funktionalität in einer Java-Anwendung zu implementieren. Wenn Sie nach allen.mp3-Dateien suchen,.class-Dateien suchen und löschen oder alle Dateien suchen müssen, auf die im letzten Monat nicht zugegriffen wurde, benötigen Sie diese Oberfläche.

Alle Klassen, die wir zur Implementierung dieser Funktionalität benötigen, sind in einem Paket zusammengefasst:

import java.nio.file.*;

2. WieFileVisitor funktioniert

Mit derFileVisitor-Schnittstelle können Sie den Dateibaum bis zu einer beliebigen Tiefe durchlaufen und Aktionen für die Dateien oder Verzeichnisse ausführen, die sich in einem beliebigen Zweig befinden.

Eine typische Implementierung derFileVisitor-Schnittstelle sieht folgendermaßen aus:

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;
    }
}

Mit den vier Schnittstellenmethoden können wir das erforderliche Verhalten an wichtigen Punkten des Traversierungsprozesses festlegen: bevor auf ein Verzeichnis zugegriffen wird, wenn eine Datei besucht wird oder wenn ein Fehler auftritt bzw. nachdem auf ein Verzeichnis zugegriffen wird.

Der Rückgabewert in jeder Stufe ist vom TypFileVisitResult und steuert den Durchfluss. Vielleicht möchten Sie den Dateibaum nach einem bestimmten Verzeichnis durchsuchen und den Vorgang beenden, wenn es gefunden wird, oder Sie möchten bestimmte Verzeichnisse oder Dateien überspringen.

FileVisitResult ist eine Aufzählung von vier möglichen Rückgabewerten für die Schnittstellenmethoden vonFileVisitor:

  • FileVisitResult.CONTINUE - Gibt an, dass der Dateibaumdurchlauf fortgesetzt werden soll, nachdem die zurückgegebene Methode beendet wurde

  • FileVisitResult.TERMINATE - Stoppt das Durchlaufen des Dateibaums und es werden keine weiteren Verzeichnisse oder Dateien besucht

  • FileVisitResult.SKIP_SUBTREE - Dieses Ergebnis ist nur dann von Bedeutung, wenn es von derpreVisitDirectory-API zurückgegeben wird. An anderer Stelle funktioniert es wieCONTINUE. Es gibt an, dass das aktuelle Verzeichnis und alle seine Unterverzeichnisse übersprungen werden sollen

  • FileVisitResult.SKIP_SIBLINGS - Gibt an, dass der Durchlauf fortgesetzt werden soll, ohne die Geschwister der aktuellen Datei oder des aktuellen Verzeichnisses zu besuchen. Wenn in der PhasepreVisitDirectory aufgerufen, wird sogar das aktuelle Verzeichnis übersprungen undpostVisitDirectory wird nicht aufgerufen

Schließlich muss es eine Möglichkeit geben, den Durchlaufprozess auszulösen, möglicherweise wenn der Benutzer nach dem Definieren von Suchkriterien auf einer grafischen Benutzeroberfläche auf die Schaltflächesearch klickt. Dies ist der einfachste Teil.

Wir müssen nur die statischewalkFileTree API derFiles Klasse aufrufen und ihr eine Instanz derPath Klasse übergeben, die den Startpunkt der Durchquerung darstellt, und dann eine Instanz unsererFileVisitor:

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

3. Beispiel für die Dateisuche

In diesem Abschnitt implementieren wir eine Dateisuchanwendung über dieFileVisitor-Schnittstelle. Wir möchten es dem Benutzer ermöglichen, den vollständigen Dateinamen mit Erweiterung und ein Startverzeichnis anzugeben, in dem gesucht werden soll.

Wenn wir die Datei finden, drucken wir eine Erfolgsmeldung auf den Bildschirm und wenn der gesamte Dateibaum durchsucht wird, ohne dass die Datei gefunden wurde, drucken wir auch eine entsprechende Fehlermeldung.

3.1. Die Hauptklasse

Wir werden diese KlasseFileSearchExample.java nennen:

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

    // standard constructors
}

Die Schnittstellenmethoden müssen noch implementiert werden. Beachten Sie, dass wir einen Konstruktor erstellt haben, der den Namen der zu suchenden Datei und den Pfad für den Beginn der Suche enthält. Wir werden den Startpfad nur als Basisfall verwenden, um zu schließen, dass die Datei nicht gefunden wurde.

In den folgenden Unterabschnitten werden wir jede Schnittstellenmethode implementieren und ihre Rolle in dieser speziellen Beispielanwendung diskutieren.

3.2. DiepreVisitDirectory API

Beginnen wir mit der Implementierung derpreVisitDirectory-API:

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

Wie bereits erwähnt, wird diese API jedes Mal aufgerufen, wenn der Prozess auf ein neues Verzeichnis in der Baumstruktur stößt. Der Rückgabewert bestimmt, was als nächstes passiert, je nachdem, was wir entscheiden. Dies ist der Punkt, an dem wir bestimmte Verzeichnisse überspringen und sie aus dem Suchbeispielbereich entfernen würden.

Lassen Sie uns keine Verzeichnisse diskriminieren und nur alle durchsuchen.

3.3. DievisitFile API

Als nächstes werden wir dievisitFile API implementieren. Hier passiert die Hauptaktion. Diese API wird jedes Mal aufgerufen, wenn eine Datei gefunden wird. Wir nutzen dies, um die Dateiattribute zu überprüfen, mit unseren Kriterien zu vergleichen und ein entsprechendes Ergebnis zu erhalten:

@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;
}

In unserem Fall überprüfen wir nur den Namen der besuchten Datei, um festzustellen, ob es sich um die Datei handelt, nach der der Benutzer sucht. Stimmen die Namen überein, drucken wir eine Erfolgsmeldung und beenden den Vorgang. Es gibt jedoch so viel zu tun, vor allem nach dem Lesen der

Hier kann man jedoch so viel tun, insbesondere nach dem Lesen des AbschnittsFile Attributes. Sie können die Erstellungszeit, die letzte Änderungszeit oder die Zeiten des letzten Zugriffs oder mehrere im Parameterattrsverfügbare Attribute überprüfen und entsprechend entscheiden.

3.4. DievisitFileFailed API

Als nächstes werden wir dievisitFileFailed API implementieren. Diese API wird aufgerufen, wenn die JVM nicht auf eine bestimmte Datei zugreifen kann. Möglicherweise wurde es von einer anderen Anwendung gesperrt, oder es könnte sich nur um ein Berechtigungsproblem handeln:

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

Wir protokollieren einfach eine Fehlermeldung und durchlaufen den Rest des Verzeichnisbaums. In einer grafischen Anwendung können Sie den Benutzer fragen, ob er ein Dialogfeld weiterhin verwenden oder nicht, oder die Nachricht einfach irgendwo protokollieren und einen Bericht für die spätere Verwendung erstellen möchten.

3.5. DiepostVisitDirectory API

Schließlich werden wir diepostVisitDirectory API implementieren. Diese API wird jedes Mal aufgerufen, wenn ein Verzeichnis vollständig durchlaufen wurde:

@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;
}

Wir verwenden dieFiles.isSameFile-API, um zu überprüfen, ob das gerade durchlaufene Verzeichnis das Verzeichnis ist, von dem aus wir das Durchlaufen gestartet haben. Wenn der Rückgabewerttrue ist, bedeutet dies, dass die Suche abgeschlossen ist und die Datei nicht gefunden wurde. Deshalb beenden wir den Prozess mit einer Fehlermeldung.

Wenn der Rückgabewert jedochfalse ist, bedeutet dies, dass wir gerade ein Unterverzeichnis durchlaufen haben und es immer noch wahrscheinlich ist, dass die Datei in einem anderen Unterverzeichnis gefunden wird. Also fahren wir mit der Durchquerung fort.

Wir können jetzt unsere Hauptmethode hinzufügen, um die AnwendungFileSearchExampleauszuführen:

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);
}

Sie können mit diesem Beispiel herumspielen, indem Sie die Werte der VariablenstartingDir undfileToSearch ändern. WennfileToSearch instartingDir oder einem seiner Unterverzeichnisse vorhanden ist, erhalten Sie eine Erfolgsmeldung, andernfalls eine Fehlermeldung.

4. Fazit

In diesem Artikel haben wir einige der weniger häufig verwendeten Funktionen untersucht, die in den Java 7 NIO.2-Dateisystem-APIs verfügbar sind, insbesondere dieFileVisitor-Schnittstelle. Wir haben es auch geschafft, eine Dateisuchanwendung zu erstellen, um deren Funktionalität zu demonstrieren.

Der vollständige Quellcode für die in diesem Artikel verwendeten Beispiele ist inGithub project verfügbar.