views:

340

answers:

5

Before debugging the late-hour-out-of-bound-recursive-function: is there a command to get subdirs? giveMeSubDirs(downToPath)?

// WARNING: RECURSION out of bound or too much data
public HashSet<FileObject> getAllDirs(String path) {
  HashSet<FileObject> checkedDirs = new HashSet<FileObject>();
  HashSet<FileObject> allDirs = new HashSet<FileObject>();

  String startingPath = path;

  File fileThing = new File(path);
  FileObject fileObject = new FileObject(fileThing);

  for (FileObject dir : getDirsInDir(path)) {

    // SUBDIR

    while ( !checkedDirs.contains(dir) 
        && !(getDirsInDir(dir.getFile().getParent()).size() == 0)) {

      // DO NOT CHECK TOP DIRS if any bottom dir UNCHECKED!

      while ( uncheckedDirsOnLevel(path, checkedDirs).size() > 0) { 

        while (getDirsInDir(path).size() == 0 
            || (numberOfCheckedDirsOnLevel(path, checkedDirs)==getDirsInDir(path).size())) {
          allDirs.add(new FileObject(new File(path)));
          checkedDirs.add(new FileObject(new File(path)));

          if(traverseDownOneLevel(path) == startingPath )
            return allDirs;

          //get nearer to the root
          path = traverseDownOneLevel(path);
        }
        path = giveAnUncheckedDir(path, checkedDirs);

        if ( path == "NoUnchecked.") {
          checkedDirs.add(new FileObject( (new File(path)).getParentFile() ));
          break;
        }
      }
    }
  }
  return allDirs;
}

Summary about the code:

  1. Go as deep to the directory tree as possible. When there is no dir in a dir, stop, put the dir to the set, traverse up. Do not check dirs in the set.
  2. Stop and return the set if you reach the starting path.
  3. Repeat steps 1 and 2.

PREMISE: the directory-structure is finite and with a small data amount.

+2  A: 

No, there is no such functionality in the Java standard API. But there is in Apache commons-io; if you don't want to include it as a library, you could also look at the source code.

Michael Borgwardt
+11  A: 

You can get all subdirs with the following snippet:

File file = new File("path");
File[] subdirs = file.listFiles(new FileFilter() {
    public boolean accept(File f) {
        return f.isDirectory();
    }
}

This gets only immediate subdirs, to retrieve all of them recursively you could write:

List<File> getSubdirs(File file) {
    List<File> subdirs = Arrays.asList(file.listFiles(new FileFilter() {
        public boolean accept(File f) {
            return f.isDirectory();
        }
    }));
    subdirs = new ArrayList<File>(subdirs);

    List<File> deepSubdirs = new ArrayList<File>();
    for(File subdir : subdirs) {
        deepSubdirs.addAll(getSubdirs(subdir)); 
    }
    subdirs.addAll(deepSubdirs);
    return subdirs;
}
pajton
+1, faster than me!
Jack
Thnx, rather unusual support:-)
pajton
I like it, very clean
John V.
@HH thnx, now corrected.
pajton
@HH `Arrays.asList` returns an immutable list apparently. So, we have to construct a new mutable `ArrayList` on top of it.
pajton
Why did you use List<File> instead of HashSet<File>? Where could you use the order?
HH
Not of any special reason. However, I couldn't use `Arrays.asList` - there is no equivalent for `HashSet`. `List` perform faster here I believe as well.
pajton
A: 
class DirFileFilter extends FileFilter {
  boolean accept(File pathname) {
    return pathname.isDirectory();
  }
}

DirFileFilter filter = new DirFileFilter();
HashSet<File> files = new HashSet<File>();

void rec(File root) {
  // add itself to the list
  files.put(root);
  File[] subdirs = root.list(filter);

  // bound of recursion: must return 
  if (subdirs.length == 0)
    return;
  else //this is the recursive case: can call itself
    for (File file : subdirs)
      rec(file);
}
Jack
Something wrong with compilation: http://stackoverflow.com/questions/2581158/java-how-to-get-all-subdirs-recursively/2584464#2584464
HH
A: 

Another version with no recursion, and alphabetical order. Also uses a Set to avoid loops (a problem in Unix systems with links).

   public static Set<File> subdirs(File d) throws IOException {
        TreeSet<File> closed = new TreeSet<File>(new Comparator<File>() {
            @Override
            public int compare(File f1, File f2) {
                return f1.toString().compareTo(f2.toString());
            }
        });
        Deque<File> open = new ArrayDeque<File>();
        open.push(d);
        closed.add(d);
        while ( ! open.isEmpty()) {
            d = open.pop();
            for (File f : d.listFiles()) {
                if (f.isDirectory() && ! closed.contains(f)) {
                    open.push(f);
                    closed.add(f);
                }
            }
        }
        return closed;
    }
tucuxi
You actually shouldn't use the java.util.Stack class, as it is broken. Use ArrayDeque instead:Deque<File> stack = new ArrayDeque<File>();
Helper Method
Good call. I have edited the code to use Deques instead.
tucuxi
Broken how, out of interest? Just wondering :)
Chris Dennett
@Chris: it uses per-method synchronization on pop, push (being based on Vector, which also likes this type of synchronization). That is an unnecessary performance hit if you are not multi-threading that code, and bad for many multi-threading scenarios where you need a larger grain of synchronization. (Looked it up after Helper's comment, as I had the same question)
tucuxi