Advanced   Java   Services DirectoryStream, PathMatcher Back Next Up Home


DirectoryStream ersetzt listFiles()

Ab Java 7 gibt es in Files die überladene statische Methode newDirectoryStream() welche die Methoden list() und listFiles() aus der Klasse File ersetzt. Das Interface DirectoryStream<T> implementiert das Interface Iterable und ist hier vom generischen Typ Path. Es gibt also eine Methode iterator die einen Iterator vom generischen Typ Path liefert. Dieser Iterator unterstützt aber keine remove() Operation. Auf Windowssystemen liefert newDirectoryStream(Path dir) ein Objekt vom Typ sun.nio.fs.WindowsDirectoryStream.

directorystream-hierarchie.jpg

DirectoryStream ist recht komfortabel zu verwenden. Da er das Interface AutoCloseable implementiert bietet sich die Verwendung von try-with-resources an. Die Methode tritt in drei verschiedenen Ausprägungen auf.

ReturntypMethode
static DirectoryStream<Path> newDirectoryStream(Path dir)
Opens a directory, returning a DirectoryStream to iterate over all entries in the directory.
static DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter)
Opens a directory, returning a DirectoryStream to iterate over the entries in the directory.
static DirectoryStream<Path> newDirectoryStream(Path dir, String glob)
Opens a directory, returning a DirectoryStream to iterate over the entries in the directory.

Nachfolgend einige Beispiele.


Alle Dateien eines Verzeichnisses auflisten

So werden alle Dateien im übergebenen Directory aufgelistet. Man sieht, daß die Methode nicht rekursiv arbeitet. Außerdem werden die Namen der Unterverzeichnisse nicht gelistet.

Path dir = Paths.get("c:/foo");

try(DirectoryStream<Path> dirStream = Files.newDirectoryStream(dir)) // liefert ein Iterable<Path>
{
   for(Path path : dirStream)
   {
      System.out.println(path);  // liefert absolute Pfade
      //System.out.println(path.getFileName()); // liefert nur den Dateinamen
   }
}
catch(IOException ex)
{
   System.out.println(ex);
}

Nur Bestimmte Dateien eines Verzeichnisses auflisten

In der Überladung der Form newDirectoryStream(Path dir, String glob) kann man den zweiten Parameter dazu benutzen einfache Filter anzugeben. Durch das folgende CodeSchnipsel werden alle Dateien aufgelistet, welche die Dateiendungen .c, .h, .cpp oder .java haben. Die Namen der Unterverzeichnisse werden nicht aufgelistet.

try(DirectoryStream<Path> dirStream = Files.newDirectoryStream(dir, "*.{c,h,cpp,java}"))
{
   for(Path path : dirStream)
   {
      System.out.println(path);
   }
}
catch(IOException ex)
{
   System.out.println(ex);
}

Eigene Filter entwerfen

Die dritte Überladung der Methode newDirectoryStream() erlaubt die Verwendung eigener Filter. Ein selbstgeschriebener Filter muß das Interface DirectoryStream.Filter<T> implementieren, also ein statisches inneres Interface von DirectoryStream.

Hier zwei Beispiele.


Ein Filter, der nur Dateien ab einer bestimmten Größe anzeigt

Der Filter sieht folgendermaßen aus.

/*
 * Ein Filter, dem man eine Dateigröße übergeben kann. Angezeigt
 * werden die Dateien, die größer sind als die übergebene Grenze.
 */
class SizeFilter implements DirectoryStream.Filter<Path>
{
   private int lowerBound;

   public SizeFilter(int lowerBound)
   {
      this.lowerBound = lowerBound;
   }

   @Override
   public boolean accept(Path entry) throws IOException
   {
      return Files.size(entry) > lowerBound;
   }
}

Wenn man den Filter geschrieben hat, übergibt man ihn einfach der passenden Überladung von newDirectoryStream(). Die Mindestdateigröße wird im Konstruktor übergeben.

Path dir = Paths.get("c:/tmp");
SizeFilter sizeFilter = new SizeFilter(3000*1024);
try(DirectoryStream<Path> dirStream = Files.newDirectoryStream(dir, sizeFilter)) // liefert ein Iterable
{
   for(Path path : dirStream)
   {
      System.out.println(path + " " + Files.size(path));
   }
}
catch(IOException ex)
{
   System.out.println(ex);
   ex.printStackTrace();
}

Ein Filter, der einen PathMatcher zum Filtern von Dateien verwendet und auch Unterverzeichnisse anzeigt

Der Quellcode der Methode DirectoryStream<Path> newDirectoryStream(Path dir, String glob) sieht wie folgt aus.

public static DirectoryStream<Path> newDirectoryStream(Path dir, String glob) throws IOException
{
   // avoid creating a matcher if all entries are required.
   if (glob.equals("*"))
      return newDirectoryStream(dir);

   // create a matcher and return a filter that uses it.
   FileSystem fs = dir.getFileSystem();
   final PathMatcher matcher = fs.getPathMatcher("glob:" + glob);
   DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter()
   {
      @Override
      public boolean accept(Path entry)
      {
          return matcher.matches(entry.getFileName());
      }
   };
   return fs.provider().newDirectoryStream(dir, filter);
}

Diesen Ansatz kopiert der folgende Filter.

/*
 * Ein Filter, der die Namen der Unterverzeichnisse anzeigt. Über den Konstruktor kann zusätzlich
 * ein String mit einem Pattern übergeben werden, das nach denselben Regeln aufgebaut sein muß
 * wie in newDirectoryStream(Path dir, String glob). Falls im Konstruktor nur das Ausgangsverzeichnis
 * angegeben wird, werden nur die Unterverzeichnisse angezeigt.
 */
class DirFilter implements DirectoryStream.Filter<Path>
{
   private String glob;
   private Path dir;

   /*
    * zeigt nur die SubDirs an
    */
   public DirFilter(Path dir)
   {
      this(dir, null);
   }

   /*
    * Zeigt die SubDirs an und die Dateien die dem Pattern entsprechen
    */
   public DirFilter(Path dir, String glob)
   {
      this.glob = glob;
      this.dir = dir;
   }

   @Override
   public boolean accept(Path entry) throws IOException
   {
      if (Files.isDirectory(entry)) return true;

      if (glob != null && !glob.equals(""))
      {
         // create a matcher and return a filter that uses it.
         FileSystem fs = dir.getFileSystem();
         PathMatcher matcher = fs.getPathMatcher("glob:" + glob);
         return matcher.matches(entry.getFileName());
      }
      return false;
   }
}

Und so kann dieser Filter verwendet werden.

DirFilter dirFilter = new DirFilter(dir, "*.{c,h,cpp,java}");
try(DirectoryStream dirStream = Files.newDirectoryStream(dir, dirFilter))
{
   for(Path path : dirStream)
   {
      System.out.print(path);
      if (Files.isDirectory(path)) System.out.println(" <dir>");
      if (Files.isRegularFile(path)) System.out.println(" <file>");
   }
}
catch(IOException ex)
{
   System.out.println(ex);
}











Valid XHTML 1.0 Strict top Back Next Up Home