D) Verzeichnisse auslesen, durchsuchen und bearbeiten

Sie kennen bereits aus dem Kapitel 09.02 Die Sicht auf das Dateisystem – java.io.File die Klasse File, ihre Funktionsweise und einige wichtige Methoden. In diesem Kapitel lernen Sie, wie Sie einige Spezialfälle am Günstigsten lösen können. Nämlich das Auslesen, Durchsuchen, Löschen und Kopieren von kompletten Verzeichnissen.

Den Inhalt eines Verzeichnisses auslesen

Um ein Verzeichnis auszulesen, stellt das Java-API schon die Methode listFiles() bzw. list() in der Klasse java.io.File bereit.

File f = new File("C:/Programme");
File[] fileArray = f.listFiles();

Zurückgeliefert wird von listFiles() ein File-Array und von list() ein String-Array, in welchem alle Dateien und Ordner in diesem Verzeichnis gespeichert werden. Damit lässt sich schon eine einfache Methode schreiben, mit dieser der Inhalt eines Verzeichnisses ausgegeben werden kann. Hilfreich ist die Methode File#isDirectory(), die testet, ob das File auf einen Ordner verweist. Beachten Sie, dass überprüft werden muss, ob das File-Array ungleich null ist, da die Methode listFiles() z. B. bei einer nicht ausreichenden Berechtigungen auf einen Ordnern null zurückliefert.

public void listDir(File dir) {

File[] files = dir.listFiles();
if (files != null) { // Erforderliche Berechtigungen etc. sind vorhanden
for (int i = 0; i < files.length; i++) { System.out.print(files[i].getAbsolutePath()); if (files[i].isDirectory()) { System.out.print(" (Ordner)\n"); } else { System.out.print(" (Datei)\n"); } } } }[/sourcecode] Leider gibt diese Methode nicht den Inhalt der evtl. vorhandenen Unterverzeichnisse aus. Dieses Problem lässt sich aber ganz einfach mit einer rekursiven Methode beheben. Zur besseren Lesbarkeit wird noch ein Präfix mit ausgegeben, das die Ausgabe entsprechend der Ordnerstruktur anpasst.

public void listDir(File dir) {
listDir(dir, „“);
}

private void listDir(File dir, String prefix) {

File[] files = dir.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) { System.out.print(prefix + files[i].getAbsolutePath()); if (files[i].isDirectory()) { System.out.print(" (Ordner)\n"); listDir(files[i], prefix + " "); // ruft sich selbst auf } else { System.out.print(" (Datei)\n"); } } } }[/sourcecode] Natürlich müssen Sie die Daten nicht sofort ausgeben, sondern können diese in bspw. einer ArrayList zwischenspeichern und zurückgeben. Im nächsten Abschnitt finden Sie hierfür auch gleich ein Beispiel.

Ein Verzeichnis durchsuchen

Prinzipiell ist es jetzt nicht mehr schwer, aus der rekursiven Auflistung eine Suche zu basteln. Es muss nur noch ein Parameter mehr übergeben werden (nämlich der Dateiname, nach welchem gesucht werden soll) und es wird ein Rückgabetyp benötigt, in welchem die Treffer gespeichert werden. In unserem Fall bedienen wir uns einer java.util.List. In der Methode wird der übergebene Dateiname nun mit dem Namen der aktuellen Datei verglichen, und im Falle eines Treffers unserer Liste hinzugefügt.

public List searchFile(File dir, String find) {

File[] files = dir.listFiles();
List matches = new ArrayList();
if (files != null) {
for (int i = 0; i < files.length; i++) { /* * Überprüft, ob der Dateiname mit dem Suchstring übereinstimmt. * Groß- und Kleinschreibung wird ignoriert. */ if (files[i].getName().equalsIgnoreCase(find)) { matches.add(files[i]); } if (files[i].isDirectory()) { // Fügt der List die List mit den Treffern aus dem Unterordner zu matches.addAll(searchFile(files[i], find)); } } } return matches; }[/sourcecode] Da es mehrere Möglichkeiten gibt, wie man nach einer Datei suchen kann (String ist im Dateinamen enthalten, Datei fängt mit String an, Datei hört mit String auf, ...), beschränkt sich diese Methode auf die Überprüfung, ob die Dateien (abgesehen von der Groß- und Kleinschreibung) exakt übereinstimmen und ist somit eher als Vorlage für eine eigene Dateisuche zu verstehen. Beachten Sie in diesem Zusammenhang die Regulären Ausdrücke.

Ein Verzeichnis löschen

Mit der Methode File#delete() kann man eine Datei oder einen Ordner löschen. Zu beachten sind folgende Punkte:

  • Nur leere Verzeichnisse können gelöscht werden.
  • Unter Umständen kann eine Datei nicht gelöscht werden (Schreibschutz, Datei wird gerade verwendet und ist deshalb gesperrt, …). Sollte dies der Fall sein, liefert delete() false zurück.

Mit diesem Wissen lässt sich unsere bisherige Methode leicht entsprechend modifizieren.

public boolean deleteDir(File dir) {

File[] files = dir.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { deleteDir(files[i]); // Verzeichnis leeren und anschließend löschen } else { files[i].delete(); // Datei löschen } } return dir.delete(); // Ordner löschen } return false; }[/sourcecode] Ein Verzeichnis kopieren

Auch hierfür muss die Methode nur geringfügig angepasst werden. Es wird nun das Quell- und Zielverzeichnis übergeben. Wie gewohnt werden alle Dateien und Ordner in einem File-Array gespeichert. Zusätzlich wird ein File-Objekt benötigt, welches den neuen Zielpfad anhand des Quellpfades für jede Datei/jeden Ordner bestimmt. Mittels File#mkdirs() wird das Zielverzeichnis inkl. allen benötigten Überordnern (sofern noch nicht vorhanden) neu angelegt. Zusätzlich legen Sie sich noch eine Methode copyFile an, die das Kopieren einer Datei übernimmt. Hierzu verwenden wir den Datenturbo Java-NIO.

public void copyDir(File quelle, File ziel) throws FileNotFoundException, IOException {

File[] files = quelle.listFiles();
/*
* In diesem Objekt wird für jedes File der Zielpfad gespeichert. 1. Der
* alte Zielpfad 2. Das systemspezifische Pfadtrennungszeichen 3. Der Name
* des aktuellen Ordners/der aktuellen Datei
*/
File newFile = null;
ziel.mkdirs(); // Erstellt alle benötigten Ordner
if (files != null) {
for (int i = 0; i < files.length; i++) { newFile = new File(ziel, files[i].getName()); if (files[i].isDirectory()) { copyDir(files[i], newFile); } else { copyFile(files[i], newFile); } } } } public void copyFile(File file, File target) throws FileNotFoundException, IOException { FileChannel in = new FileInputStream(file).getChannel(); FileChannel out = new FileOutputStream(target).getChannel(); in.transferTo(0, file.length(), out); in.close(); out.close(); }[/sourcecode] Die Größe eines Verzeichnisses bestimmen

Mal wieder ein Fall für die Rekursion. Mit File#length() bekommt man die Größe der Datei in byte als long zurückgeliefert. Diese wird für alle Dateien im aktuellen Verzeichnis mitsamt der rekursiv ermittelten Größe der Unterverzeichnisse aufaddiert.

public long getDirSize(File dir) {

long size = 0;
File[] files = dir.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { size += getDirSize(files[i]); // Gesamtgröße des Verzeichnisses aufaddieren } else { size += files[i].length(); // Größe der Datei aufaddieren } } } return size; }[/sourcecode]

10 Replies to “D) Verzeichnisse auslesen, durchsuchen und bearbeiten”

  1. ChrisJavaNewbie

    Als Java-Noob hätte ich folgende Frage:

    WIE bekomme ich es hin, das das Verzeichnis ausgelesen wird, in eine TXT-umgewandelt wird und mir dann als email zugesandt wird ?

    Danke,
    Chris

  2. Stefan Kiesel

    Auslesen des Verzeichnisses steht ja oben. Das, was in die TXT-Datei soll, kann mit einem FileWriter geschrieben werden. Der Mailversand kann über die Java Mail-API erfolgen.

  3. ChrisJavaNewbie

    Danke – Dass der „Inhalt eines Verzeichnisses ausgelesen“ werden kann, habe ich schon bemerkt.

    Doch erfolgt die Ausgabe am Bildschirm, oder ?

    Wie müsste der Code nun aussehen:

    – damit das ganze in eine TXT-Datei umgeleitet wird

    – diese TXT-Datei mir als email zugeschickt wird ?

    Chris

  4. Stefan Kiesel

    Hi Chris,

    sorry aber komplette Programme werde ich hier nicht liefern. Wenn man programmieren lernen möchte, sollte man mehr Eigeninitiative zeigen. Wenn man nicht programmieren lernen möchte sondern nur ein Programm benötigt, muss man jemanden dafür bezahlen.

    Grüße
    Stefan

  5. ChrisJavaNewbie

    Alles klar, kenne den Entwicklungsaufwand von der VBA-Seite her.

    Wie wäre es trotzdem mit nem „Schubser“ in die richtige Richtung ? (zB. weiterführende Links ?)

    Danke,
    Chris

  6. Stefan Kiesel

    Anstatt der Ausgabe auf der Konsole (sysouts) einfach in einen StringBuilder oder ähnliches schreiben (wenn man schon in einer anderen Sprache programmieren kann, sollte das ja nicht das Problem sein). Daraus kann man dann eine Zeichenkette generieren und diese über die Java Mail API verschicken.

    Grüße
    Stefan

  7. ChrisJavaNewbie

    Danke

    Ich werde es vorerst in diese Richtung versuchen.

    Hoffe, wenn ich dabei stecke, dass ich mich wieder melden darf.

    Gruß,
    Chris

  8. Stefan Kiesel

    Natürlich. Aber ehrlich gesagt bekommen Sie vermutlich schneller Hilfe, wenn Sie es in einem Forum mit mehreren Teilnehmer versuchen.

    Grüße
    Stefan

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.