Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage |
<< | < | > | >> | API | Kapitel 22 - Datei- und Verzeichnis-Handling |
Wurde ein File-Objekt für ein Verzeichnis konstruiert, so stehen weitere Methoden zur Verfügung, um auf die zusätzlichen Funktionen eines Verzeichnisses zuzugreifen. Mit Hilfe der Methode list ist es beispielsweise möglich, den Inhalt des Verzeichnisses auszulesen:
public String[] list() |
java.io.File |
list liefert ein Array von Strings, das für jeden gefundenen Verzeichniseintrag ein Element enthält. Die Liste enthält die Namen aller Dateien und Unterverzeichnisse mit Ausnahme von . und ... list gibt es noch in einer zweiten Variante, bei der die Auswahl der Verzeichniseinträge eingeschränkt werden kann. Dabei muss ein Objekt übergeben werden, das das Interface FilenameFilter implementiert. Dieses besitzt eine Methode accept, die für jede gefundene Datei aufgerufen wird und entscheidet, ob sie in die Liste aufgenommen werden soll oder nicht.
Zusätzlich gibt es die statische Methode listRoots, mit der eine Liste aller »Wurzeln« der verfügbaren Dateisysteme beschafft werden kann. Unter UNIX gibt es lediglich die Wurzel »/«, unter Windows dagegen eine für jeden Laufwerksbuchstaben.
Eine häufig benötigte Funktion besteht darin, ein Verzeichnis samt seiner Unterverzeichnisse rekursiv zu durchlaufen und bei jedem gefundenen Eintrag eine bestimmte Aufgabe zu erledigen. Wir wollen zeigen, wie mit Hilfe des Visitor-Pattern (siehe Abschnitt 11.4.8) eine universell verwendbare Lösung geschaffen werden kann. Zunächst definieren wir dazu ein Interface DirectoryVisitor:
001 /* DirectoryVisitor.java */ 002 003 import java.io.*; 004 005 public interface DirectoryVisitor 006 { 007 public void enterDirectory(File dir); 008 public void leaveDirectory(File dir); 009 public void visitFile(File file); 010 } |
DirectoryVisitor.java |
Beim Betreten eines Verzeichnisses wird enterDirectory aufgerufen, beim Verlassen leaveDirectory. Zu jedem darin enthaltenen Dateieintrag wird visitFile aufgerufen. Um es der konkreten Visitor-Implementierung so einfach wie möglich zu machen, werden sowohl Verzeichnisse als auch Dateien als fertige File-Objekte übergeben.
Ein konkreter Visitor, der eine Verzeichnisstruktur mit den darin enthaltenen Dateien und Unterverzeichnissen korrekt eingerückt auf dem Bildschirm ausgibt, entsteht durch Implementieren von DirectoryVisitor wie folgt:
001 /* DirectoryPrintVisitor.java */ 002 003 import java.io.*; 004 005 public class DirectoryPrintVisitor 006 implements DirectoryVisitor 007 { 008 String indent = ""; 009 010 public void enterDirectory(File dir) 011 { 012 System.out.println(indent + "[" + dir.getName() + "]"); 013 indent += " "; 014 } 015 016 public void leaveDirectory(File dir) 017 { 018 indent = indent.substring(2); 019 } 020 021 public void visitFile(File file) 022 { 023 System.out.println(indent + file.getName()); 024 } 025 } |
DirectoryPrintVisitor.java |
In ähnlicher Weise kann ein DirectoryVisitor geschrieben werden, der die Anzahl der Dateien und Verzeichnisse zählt und die kumulierte Größe der darin enthaltenen Dateien ermittelt:
001 /* DirectorySizeVisitor.java */ 002 003 import java.io.*; 004 005 public class DirectorySizeVisitor 006 implements DirectoryVisitor 007 { 008 int files = 0; 009 int dirs = 0; 010 long size = 0; 011 012 public void enterDirectory(File dir) 013 { 014 ++dirs; 015 } 016 017 public void leaveDirectory(File dir) 018 { 019 } 020 021 public void visitFile(File file) 022 { 023 ++files; 024 size += file.length(); 025 } 026 027 public int getDirs() 028 { 029 return dirs; 030 } 031 032 public int getFiles() 033 { 034 return files; 035 } 036 037 public long getSize() 038 { 039 return size; 040 } 041 } |
DirectorySizeVisitor.java |
Nun fehlen nur noch die generische Methode für den rekursiven Verzeichnisdurchlauf und ein Beispielprogramm, das die Anwendung der Klassen im Zusammenspiel zeigt:
001 /* Listing2205.java */ 002 003 import java.io.*; 004 005 public class Listing2205 006 { 007 static void traverse(File dir, DirectoryVisitor visitor) 008 { 009 if (!dir.isDirectory()) { 010 throw new IllegalArgumentException( 011 "not a directory: " + dir.getName() 012 ); 013 } 014 visitor.enterDirectory(dir); 015 File[] entries = dir.listFiles( 016 new FileFilter() 017 { 018 public boolean accept(File pathname) 019 { 020 return true; 021 } 022 } 023 ); 024 for (int i = 0; i < entries.length; ++i) { 025 if (entries[i].isDirectory()) { 026 traverse(entries[i], visitor); 027 } else { 028 visitor.visitFile(entries[i]); 029 } 030 } 031 visitor.leaveDirectory(dir); 032 } 033 034 public static void main(String[] args) 035 { 036 File file = new File(args[0]); 037 //Bildschirmausgabe der Struktur 038 traverse(file, new DirectoryPrintVisitor()); 039 //Größen ermitteln 040 DirectorySizeVisitor visitor = new DirectorySizeVisitor(); 041 traverse(file, visitor); 042 System.out.println("directories: " + visitor.getDirs()); 043 System.out.println("files: " + visitor.getFiles()); 044 System.out.println("size: " + visitor.getSize()); 045 } 046 } |
Listing2205.java |
Die eigentliche Arbeit wird von traverse erledigt. Sie stellt zunächst sicher, dass das übergebene File-Objekt auch tatsächlich ein Verzeichnis darstellt, und nicht etwa eine Datei. Ist das der Fall, wird auf dem übergebenen Visitor enterDirectory aufgerufen und mit listFiles eine Liste aller im Verzeichnis enthaltenen Dateien und Unterverzeichnisse beschafft. Zu jedem Unterverzeichnis erfolgt ein rekursiver Aufruf von traverse, zu jeder Datei wird visitFile aufgerufen. Nachdem alle Einträge abgearbeitet sind, wird das dem Visitor durch Aufruf von leaveDirectory mitgeteilt.
Neben dem Zugriff auf die Verzeichniseinträge gibt es in der Klasse File auch Methoden, um Dateien oder Verzeichnisse zu löschen oder umzubenennen und um Verzeichnisse neu anzulegen:
public boolean mkdir() public boolean mkdirs() public boolean renameTo(File dest) public boolean delete() |
java.io.File |
Die Methode delete löscht die durch das File-Objekt bezeichnete Datei. Mit renameTo wird das File-Objekt in das als Parameter übergebene Objekt umbenannt. Durch Aufruf von mkdir wird das durch das File-Objekt spezifizierte Verzeichnis angelegt. Mit mkdirs werden sogar alle Vaterverzeichnisse automatisch angelegt, wenn sie noch nicht existieren. Alle Methoden geben true zurück, wenn sie ihre Aufgabe erfolgreich ausführen konnten. Andernfalls geben sie false zurück.
Das folgende Listing zeigt die Verwendung der Klasse File und den Aufruf verschiedener Methoden:
001 /* TestFile.java */ 002 003 import java.io.*; 004 import java.util.*; 005 006 public class TestFile 007 { 008 public static void main(String[] args) 009 { 010 File fil = new File("TestFile.java"); 011 TestFile.printFileInfo(fil); 012 fil = new File(".."); 013 TestFile.printFileInfo(fil); 014 } 015 016 static void printFileInfo(File fil) 017 { 018 System.out.println("Name= "+fil.getName()); 019 System.out.println("Path= "+fil.getPath()); 020 System.out.println("AbsolutePath= "+fil.getAbsolutePath()); 021 System.out.println("Parent= "+fil.getParent()); 022 System.out.println("exists= "+fil.exists()); 023 System.out.println("canWrite= "+fil.canWrite()); 024 System.out.println("canRead= "+fil.canRead()); 025 System.out.println("isFile= "+fil.isFile()); 026 System.out.println("isDirectory= "+fil.isDirectory()); 027 if (fil.isDirectory()) { 028 String[] fils = fil.list(); 029 for (int i=0; i<fils.length; ++i) { 030 System.out.println(" "+fils[i]); 031 } 032 } 033 System.out.println("isAbsolute= "+fil.isAbsolute()); 034 System.out.println( 035 "lastModified= "+(new Date(fil.lastModified())) 036 ); 037 System.out.println("length= "+fil.length()); 038 System.out.println(""); 039 } 040 } |
TestFile.java |
Ein Aufruf des Programms liefert folgende Ausgabe:
Name= TestFile.java
Path= TestFile.java
AbsolutePath= C:\ARC\DOKU\java\examples\TestFile.java
Parent= null
exists= true
canWrite= true
canRead= true
isFile= true
isDirectory= false
isAbsolute= false
lastModified= Sun Jan 05 17:15:56 1997
length= 1242
Name= ..
Path= ..
AbsolutePath= C:\ARC\DOKU\java\examples\..
Parent= null
exists= true
canWrite= true
canRead= true
isFile= false
isDirectory= true
makefile
html.cfg
...
jdbc.sgml
tuning.sgml
reflection.sgml
isAbsolute= false
lastModified= Wed Jul 22 16:55:32 GMT+02:00 1998
length= 0
Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage, Addison Wesley, Version 7.0 |
<< | < | > | >> | API | © 1998, 2011 Guido Krüger & Heiko Hansen, http://www.javabuch.de |