Rekursive File Listing mit Abstrakten Datentyp

mbecker

Mitglied
Hallo,

ich will ein Verzeichnis durchsuchen inkl. der Unterordner und alle Dateien in einem Abstrakten Datentyp speichern, so dass die Dateien eine Beziehung zu ihren Ordnern haben.

Bsp. Ordnerstruktur:
PHP:
Hauptverzeichnis
  Ordner 1
     Datei 1.1
     Datei 1.2
  Ordner 2
     Datei 2.1
     Datei 2.2

Es wird nun das Hauptverzeichnis aufgerufen und die Ordner und die Dateien sollen gespeichert werden. Aber jeweils, so dass man rekonstruieren kann, welche Datei zu welchem Ordner gehört (bzw. welcher Unterordner zu welchem Ordner, etc.).

Ich hab daran gedacht, die Dateien/Ordner in einem Abstrakten Datentyp zu speichern (Welcher ist hier am besten geeignet?). Dabei würde ich jede Datei/Ordner als Objekt mit den Attributen Name, ID und ParentID sehen.

Mein Problem ist es nun, dass ich nicht hin bekomme, dass diese Beziehungen zustande kommen.

Habt ihr evtl. einen Denkansatz, der mir weiterhilft oder schon eine Idee der Implemntierung?

ich danke euch schon mal für eure Bemühungen! :)
 
Wie mahe schon sagte. Du kannst einfach java.io.File verwenden.
File kennt die Methoden getParentFile() um das Verzeichnis der Datei herauszufinden und listFiles() um die im Verzeichnis enthalteten Files zu bekommen. Und mit isDirectory und isFile() findest du raus obs ein Verzeichnis oder File ist.
Und dann einfach eine rekursive Funktion machen. Mit den Parents und listFiles() kannst du dann die Struktur rekonstruiren
Java:
public void foo(File directory)
for(File f : directory.listFiles()) {
    if(f.isDirectory()) {
        foo(f)
    }
    else (
        // Lege irgendwelche Filearrays an oder Instanzen deiner eigenen Klasse
    }
}

Ich weiss man sollte keine Lösungen posten, aber hier noch was interessantes das sich mit dem Visitor-Pattern realisieren lässt (kopiert von http://www.javabuch.de/)
Schaus dir einfach mal an ;) Die Ausgabe sieht dann so aus:
Code:
[Program Files]
  [Adobe]
    [Reader 9.0]
      [Esl]
        AiodLite.dll
      Liesmich.htm
      [Reader]
        A3DUtility.exe
        ACE.dll
        AcroBroker.exe
        Acrofx32.dll
        AcroRd32.dll[...]

Java:
import java.io.File;

public interface DirectoryVisitor {
	public void enterDirectory(File dir);

	public void leaveDirectory(File dir);

	public void visitFile(File file);
}
Java:
import java.io.File;

public class DirectoryPrintVisitor implements DirectoryVisitor {
	String indent = "";

	public void enterDirectory(File dir) {
		System.out.println(indent + "[" + dir.getName() + "]");
		indent += "  ";
	}

	public void leaveDirectory(File dir) {
		indent = indent.substring(2);
	}

	public void visitFile(File file) {
		System.out.println(indent + file.getName());
	}
}
Java:
import java.io.File;

public class DirectorySizeVisitor implements DirectoryVisitor {
	int files = 0;
	int dirs = 0;
	long size = 0;

	public void enterDirectory(File dir) {
		++dirs;
	}

	public void leaveDirectory(File dir) {
	}

	public void visitFile(File file) {
		++files;
		size += file.length();
	}

	public int getDirs() {
		return dirs;
	}

	public int getFiles() {
		return files;
	}

	public long getSize() {
		return size;
	}
}
Java:
import java.io.File;
import java.io.FileFilter;

public class Main {
	static void traverse(File dir, DirectoryVisitor visitor) {
		if (!dir.isDirectory()) {
			throw new IllegalArgumentException("not a directory: "
					+ dir.getName());
		}
		visitor.enterDirectory(dir);
		File[] entries = dir.listFiles(new FileFilter() {
			public boolean accept(File pathname) {
				return true;
			}
		});
		for (int i = 0; i < entries.length; ++i) {
			if (entries[i].isDirectory()) {
				traverse(entries[i], visitor);
			} else {
				visitor.visitFile(entries[i]);
			}
		}
		visitor.leaveDirectory(dir);
	}

	public static void main(String[] args) {
		File file = new File("%USERNAME%Pictures"); // Ändern
		// Bildschirmausgabe der Struktur
		traverse(file, new DirectoryPrintVisitor());
		// Größen ermitteln
		DirectorySizeVisitor visitor = new DirectorySizeVisitor();
		traverse(file, visitor);
		System.out.println("directories: " + visitor.getDirs());
		System.out.println("files: " + visitor.getFiles());
		System.out.println("size: " + visitor.getSize());
	}
}
Anstatt eine Ausgabe zu machen, könntest du jetzt irgendwelche File-Arrays anlegen oder Instanzen deiner eigenen Fileklasse erstellen oder was weiss ich.
 
Zuletzt bearbeitet:
Vielen Dank schon mal für eure Antworten und Bemühungen!

Ein rekursives File Listing mit Hilfe von java.io.file will ich explizit nicht, weil ich die das Hauptverzeichnis einmal durchsuchen lassen möchte und alle darin enthaltenen Dateien und Ordner speichern will, um so schneller und auf jede einzelne Instanz zugreifen zu können.

Vielen Dank auch für das Posting des Codes. Wie gesagt ist ein "einfaches" rekursives File Listing nicht mein Ziel.
 
Irgendwie verstehe ich das Problem nicht ganz. Wenn du ein File-Objekt hast, weißt du doch zu welchem Ordner deine Datei gehört (getParentFile()).
 
Ist mir auch nicht ganz klar, worauf du eigentlich rauswillst...
Wie genau definierst du denn kein einfaches rekursives File-Listing?

Du sagst, dass du kein java.io.File-Objekt benutzen willst, aufgrund der Geschwindigkeit. Wenn du aber nicht gerade eine Abbildung in Hash-Maps oder Ähnlichem basteln willst, existiert eigentlich kein Geschwindigkeits-Unterschied, ob du jetzt einen eigenen Datentyp oder die java.io.File-Klasse verwendest...

Und wie zeja schon geschrieben hat, ein File-Objekt enthält alle Datei-Attribute, Kind-Dateien, Eltern-Dateien... Alles was du für ein eigenes File-Listing brauchst.
 
Vielleicht bin ich tatsächlich auf dem Holzweg jede Datei und deren Beziehung zum Ordner intern zu speichern.

Mein Ziel ist eine grafische Visualisierung der Ordnerstruktur zu erstellen (siehe Anhang). Ein weiteres Bsp. ist unter http://www.randelshofer.ch/treeviz/ zu finden.

Ich denke einfach, dass ich jede Datei intern einzeln abspeichern muss, um bei der grafischen Darstellung die Beziehung zu dem übergeordneten Ornder herstellen zu können (sowie den Punkt speichern zu können, an dem die Datei später grafisch dargsetllt wird).
 

Anhänge

  • dirlisting.jpg
    dirlisting.jpg
    27,7 KB · Aufrufe: 39
Sowas ist natürlich cool... Hab mir auch mal vorgenommen, sowas zu basteln ;)

Ob du jetzt jede einzelne Datei als eigenes java.io.File speicherst und je nach Bedarf die Eltern oder Kinder abfragst, oder eine einzelne Datei als Startpunkt nimmst und dich durch die Hierarchie hangelst bleibt ja dir überlassen.

Also IMHO brauchst du eigentlich nur diesen einen Datentyp.

Ich kann jetzt aber auch verstehen, was du mit der Performance gemeint hast. Um die Beziehung eines Files zu seiner Umgebung auszulesen, musst du dich überall durchhangeln... Aber ich denke nicht, dass du eine effizientere Struktur bauen kannst, als die der java.io.File-Klasse. Vielleicht fehlt mir aber auch einfach das Verständnis für diese Art von Materie ;)
 
Also gehts hier im Grunde gar nicht um die Files sondern darum was das für eine Datenstruktur ist?

Das ganze ist ein Graph, genauer genommen ein Baum, da ein Kind keine zwei Eltern hat.

Grunde reicht also die Standard Baumstruktur wie:

Java:
public interface TreeNode<T> {

   public TreeNode<T> getParent();
   public List<TreeNode<T>> getChildren();
   public T getData();

}

Als Data nimmst du dein File-Objekt.
 
Vielen Dank zeja!

Deine Antwort war der entscheidende Hinweis!

Ich habe zwar nicht viel über die Implementierung oder Dokumentation von "TreeNode" gefunden, dafür mehr über "DefaultMutableTreeNode" in Zusammenhang mit JTree. Ich habe mir deshalb "DefaultMutableTreeNode" zu eigen gemacht und die Files (vorerst nur deren Namen) in die Baumstruktuer gespeichert:

Java:
import java.io.File;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;

public class Tree {
	public DefaultMutableTreeNode treeNode;
	
	public Tree() {
		this.treeNode = new DefaultMutableTreeNode("Ebooks", true);
		listFiles("C:\\DirTest", this.treeNode);
		printTree(this.treeNode, 0);
	}
	
	public void listFiles(String dir, DefaultMutableTreeNode parent){
		File[] files = new File(dir).listFiles();
		
		for (int i = 0; i < files.length; i++) {
			DefaultMutableTreeNode node = new DefaultMutableTreeNode(files[i].getName());
			if(files[i].isDirectory()){
				parent.add(node);
				listFiles(files[i].getAbsolutePath(), node);
			} else {
				parent.add(node);				
			}
		}
	}
	
	public void printTree(TreeNode tree, int a){
		//System.out.println(tree.getChildCount());
		for(int i = 0; i < tree.getChildCount(); i++){
			if(tree.getChildAt(i).getChildCount() < 1){
				for(int x = 0; x < a; x++){ System.out.print(" "); }
				System.out.print("|-");
				System.out.println(i + "." + tree.getChildAt(i));
			} else {
				for(int x = 0; x < a; x++){ System.out.print(" "); }
				System.out.print("|-");
				System.out.println(i + "." + tree.getChildAt(i));
				a++;
				printTree(tree.getChildAt(i), a);
				a = 0;
			}
		}
	}
}

Ausgabe:
PHP:
|-0.Test.pdf
|-1.Test 1
 |-0.Test 1.1.txt
 |-1.Test 1.2.txt
 |-2.Test 1.3
  |-0.Test 1.3.1.txt
|-2.Test 2
 |-0.Test 2.1.txt

Ist der Ansatz richtig oder kann man das besser implemntieren?
Hast du evtl. noch ein paar Informationen über TreeNode?

Angenommen ein ChildNode hat mehrer Eltern. Hast du vlt. noch einen kleinen Hinweis, wie man das realisieren könnte?
 
Zuletzt bearbeitet von einem Moderator:

Neue Beiträge

Zurück