4

I have a question which could be language-agnostic but for this particular implementation I'm using Java. It is possible and relatively trivial to list the folders in a directory - using a function like this:

private DefaultMutableTreeNode GenerateFSTree(File f)
{
    int i = 0;
    File[] Children = f.listFiles();

    DefaultMutableTreeNode x = new DefaultMutableTreeNode(f.getName());

    if ( Children != null )
    {
        for ( i = 0; i < Children.length; i++ )
        {
            File f_cur = Children[i];
            if (
            f_cur.isDirectory() && 
            ( this.DisplayHidden || !f_cur.isHidden() ) 
            )
            {   
                x.add(GenerateFSTree(f_cur));
            }
        }
    }

    return x;
}

As you can see this makes heavy use of recursion to evaluate the filesystem and what you end up with is a tree of DefaultMutableTreeNode items.

Now my question is - is there a faster way to do this? There must be, because this is slow. Try executing this on / and it takes forever. Yet if I use say Nautilus or the built-in Java File selection dialog, the tree renders instantly.

So my question is - how can I speed this up?

Thanks

  • 3
    I would guess this "fastness" of Nautilus or whatever comes, because the tree is only loaded partwise (e.g. what you see in this moment). But that's just a guess. – cyphorious Aug 30 '10 at 17:58
  • 1
    Does this even work? Ever heard of tail recursion? – Hamish Grubijan Aug 30 '10 at 17:59
  • 2
    I would imagine the Java File selection dialog is being lazy, literally. In order to show a standard "select file" dialog you only need to show the parents (recursively) of the current location and the current location's contents, not the whole file system tree. So it's probably using the same APIs are you, just only running them when it needs to. – Mike Q Aug 30 '10 at 18:01
  • cyphorious - I'd be inclined to agree looking at the answers. Hamish - it could be written that way but I doubt it would make the routine any more efficient - tail recursion is still recursion and I suspect the problem here is the sheer number of branches, particularly evaluating say /usr. –  Aug 30 '10 at 18:56

2 Answers2

4

The normal way to do this is to only read a single directory at first. Any directories under that top level directory will not be read immediately. Instead a dummy node will be inserted under the directory tree node that is created. When the user expands the directory node the program then reads the relevant directory and then replaces the dummy node with nodes that reflect the contents of the directory.

Russ Hayward
  • 5,617
  • 2
  • 25
  • 30
2

take a look at this example http://www.java2s.com/Code/Java/Swing-JFC/FileTree.htm
this treemodel will provide the filesystem structure to your jtree. the file system is only accessed when expanding a node... and initially for the root node. ;)

class FileTreeModel implements TreeModel {
    protected File root;
    public FileTreeModel(File root) { this.root = root; }

    public Object getRoot() { return root; }

    public boolean isLeaf(Object node) {  return ((File)node).isFile(); }

    public int getChildCount(Object parent) {
        String[] children = ((File)parent).list();
        if (children == null) return 0;
    return children.length;
    }

    public Object getChild(Object parent, int index) {
        String[] children = ((File)parent).list();
        if ((children == null) || (index >= children.length)) return null;
    return new File((File) parent, children[index]);
    }

    public int getIndexOfChild(Object parent, Object child) {
        String[] children = ((File)parent).list();
        if (children == null) return -1;
            String childname = ((File)child).getName();
            for(int i = 0; i < children.length; i++) {
                if (childname.equals(children[i])) return i;
            }
            return -1;
    }

    public void valueForPathChanged(TreePath path, Object newvalue) {}

    public void addTreeModelListener(TreeModelListener l) {}
    public void removeTreeModelListener(TreeModelListener l) {}


}

usage

Jtree tree = new JTree(new FileTreeModel(new File("/")));

this model will prevent you from filling up your memory with DefaultTreeNodes and minimizes the access to the underlying filesystem.

Marc-Christian Schulze
  • 3,154
  • 3
  • 35
  • 45