Advanced   Java   Services FileVisitor und die Methode Files.walkFileTree() Back Next Up Home


FileVisitor und die Methode Files.walkFileTree()

Mit dem Interface FileVisitor<T> und der Methode walkFileTree() aus der Klasse Filesgibt es ab Java 7 eine einfache Möglichkeit ein Verzeichnis und dessen Inhalt rekursiv zu durchlaufen. Der Methode walkFileTree() übergibt man eine Implementierung des Interfaces und die Methode erledigt dann die Rekursion. Die Klasse SimpleFileVisitor<T> ist zudem eine einfache Realisierung des Interfaces FileVisitor<T> mit leeren Methoden.






FileVisitor und FileVisitResult

Der FileVisitor vereinbart vier Methoden. ReturnTyp ist jeweils das Enum FileVisitResult.



Modifier and TypeMethod and Description
FileVisitResultpreVisitDirectory(T dir, BasicFileAttributes attrs)
Invoked for a directory before entries in the directory are visited.
FileVisitResultpostVisitDirectory(T dir, IOException ex)
Invoked for a directory after entries in the directory, and all of their descendants, have been visited.
FileVisitResultvisitFile(T file, BasicFileAttributes attrs)
Invoked for a file in a directory.
FileVisitResultvisitFileFailed(T file, IOException ex)
Invoked for a file that could not be visited.
Enum ConstantDescription
CONTINUEContinue.
SKIP_SIBLINGSContinue without visiting the siblings of this file or directory.
SKIP_SUBTREEContinue without visiting the entries in this directory.
TERMINATETerminate.

Es folgen einige Beispiele.





Ein FileVisitor, der die Dateien und Verzeichnisse zählt, die er besucht.

Wir implementieren hier das Interface selbst.

import java.nio.file.Path;
import java.io.IOException;
import java.nio.file.FileVisitor;
import java.nio.file.FileVisitResult;
import java.nio.file.attribute.BasicFileAttributes;

public class MyFileVisitor implements FileVisitor<Path>
{
   private int fileCount = 0;
   private int dirCount = 0;

   /**
    * Hier ist Path immer ein Directory der Größe 0
    */
   @Override
   public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes bfa) throws IOException
   {
      System.out.println("preVisitDirectory: " + path + " size = " + bfa.size() + " bytes");
      dirCount++;
      return FileVisitResult.CONTINUE;
   }

   /**
    * Hier ist Path immer ein Directory der Größe 0
    * ex = null wenn keine Exception aufgetreten ist
    */
   @Override
   public FileVisitResult postVisitDirectory(Path path, IOException ex) throws IOException
   {
      System.out.println("postVisitDirectory: " + path + " Exception = " + ex);
      return FileVisitResult.CONTINUE;
   }

   /**
    */
   @Override
   public FileVisitResult visitFile(Path path, BasicFileAttributes bfa) throws IOException
   {
      System.out.println("visitFile: " + path + " size = " + bfa.size() + " bytes");
      fileCount++;
      return FileVisitResult.CONTINUE;
   }

   /**
    */
   @Override
   public FileVisitResult visitFileFailed(Path path, IOException ex) throws IOException
   {
      System.out.println("visitFileFailed " + " Exception = " + ex);
      return FileVisitResult.CONTINUE;
   }

   public int getFileCount()
   {
      return fileCount;
   }

   public int getDirCount()
   {
      return dirCount;
   }
}

main kann etwa so aussehen.

import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;
import java.nio.file.Files;

public class WalkFileTree_01
{
   public static void main(String[] args)
   {
      Path path = Paths.get("c:/tmp");

      MyFileVisitor fileVisitor = new MyFileVisitor();

      try
      {
         Files.walkFileTree(path, fileVisitor);
         System.out.print("found: " + fileVisitor.getFileCount() + " files in ");
         System.out.println(fileVisitor.getDirCount()+ " directories");
      }
      catch(IOException ex)
      {
         ex.printStackTrace();
      }
   }
}

Eine mögliche Ausgabe

preVisitDirectory: c:\tmp size = 0 bytes
visitFile: c:\tmp\datei.c size = 6 bytes
visitFile: c:\tmp\datei.cpp size = 0 bytes
visitFile: c:\tmp\datei.h size = 0 bytes
visitFile: c:\tmp\datei.java size = 4 bytes
...
preVisitDirectory: c:\tmp\java size = 0 bytes
postVisitDirectory: c:\tmp\java Exception = null
...
postVisitDirectory: c:\tmp Exception = null
found: 57 files in 19 directories

Ein FileVisitor, der den PathMatcher verwendet und dem man ein Suchpattern übergeben kann

In diesem Beispiel stützen wir uns auf den SimpleFileVisitor und überschreiben lediglich die notwendigen Methoden. Statt eines Konstruktors verfügt der SearchFileVisitor über eine statische Methode searchFor der man alle Parameter übergeben kann und die die gefundenen Dateien in einer Liste liefert. Dazu verwenden wir das Interface PathMatcher. Eion Objekt der implementierenden Klasse erhält man über das Defaultdateisystem.

public class SearchFileVisitor implements FileVisitor<Path>
{
   private String searchPattern = "";
   private List<Path> searchList;

   /**
      zulässige Pattern
      * steht für eine Gruppe von Buchstaben, die für Dateinamen zulässig sind: "abc*.*"
      ? steht für einen Buchstaben, der für Dateinamen zulässig ist: "abc?fg?.j*"
    */
   public static List<Path> searchFor(Path startDir, String searchPattern, boolean searchInFile) throws IOException
   {
      SearchFileVisitor fileVisitor = new SearchFileVisitor(searchPattern);
      Files.walkFileTree(startDir, fileVisitor);

      return fileVisitor.getResultList();
   }

   // private constructor
   private SearchFileVisitor(String searchPattern)
   {
      this.searchPattern = searchPattern;
      this.searchList = new ArrayList<>();
   }

   /**
    */
   @Override
   public FileVisitResult visitFile(Path path, BasicFileAttributes bfa) throws IOException
   {
      
      FileSystem fileSystem = FileSystems.getDefault();
      PathMatcher pathMatcher = fileSystem.getPathMatcher("glob:" + searchPattern);
      // Man muß zum Vergleich den reinen Dateinamen nehmen ohne Pfad !!!
      if (pathMatcher.matches(path.getFileName()))
      {
         searchList.add(path);
      }
      return FileVisitResult.CONTINUE;
   }

   /**
    */
   @Override
   public FileVisitResult visitFileFailed(Path path, IOException ex) throws IOException
   {
      System.out.println("visitFileFailed " + " Exception = " + ex);
      return FileVisitResult.CONTINUE;
   }


   public List<Path> getResultList()
   {
      return searchList;
   }
}

Ein mögliches main

public static void main(String[] args)
{
   try
   {
      Path startDir = Paths.get("c:/tmp");
      String searchPattern = "*.{txt,java}";;
      boolean searchInFile = false;
      // Geht rekursiv durch alle Unterverzeichnisse
      // Rekursion wird in der Methode walkFileTree() gemacht
      List<Path> result = SearchFileVisitor.searchFor(startDir, searchPattern, searchInFile);
      for(Path path : result)
      {
         System.out.println(path + " size = " + Files.size(path) + " bytes" );
      }
   }
   catch(IOException ex)
   {
      ex.printStackTrace();
   }
}

Eine mögliche Ausgabe

c:\tmp\datei.java size = 4 bytes
c:\tmp\datei.txt size = 25 bytes
c:\tmp\dokument.txt size = 11 bytes
c:\tmp\nochnedatei.java size = 4 bytes
c:\tmp\tempdir\dokument.txt size = 48 bytes

Valid XHTML 1.0 Strict top Back Next Up Home