Visualizing directories

How do I plot the content of a directory and all its subdirectories into infinity using TreeForm? I've tried using a mix of FileNames, StringSplit and GatherBy but in the end I couldn't find even a promising start.

-
Does it have to be TreeForm? Could it be TreePlot? –  Joel Klein Jan 7 '13 at 3:37
Yes, that would work too (I choose TreeForm because I thought formatting the list in that way would not be too hard). –  Pickett Jan 7 '13 at 3:53
Take a look at the makeTree function in Leonid's answer on implementing Tries. By redefining the RHS of the first line in the definition as makeTree[StringSplit[wrds, "/"]], you can get a good structure for the directory tree with makeTree@FileNames["*", {"*"}, ∞] (you'll have to clean up the {{} -> {}}). While this can't be plugged in a built-in graph function like Graph or TreePlot, it can be easily converted to a graph using some custom code. –  rm -rf Jan 7 '13 at 4:48
An alternatieve presentation here: mathematica.stackexchange.com/a/6200/57 –  Sjoerd C. de Vries Jan 7 '13 at 6:27
Thx @Hypnotoad your solution worked well. Posted it below. (Thx to everyone else as well!) –  Pickett Jan 7 '13 at 20:36

Here's a relatively straightforward "first version":

ellipsizeMax = 8;
ellipsize[str_] := If[StringLength[str] > ellipsizeMax, StringTake[str, ellipsizeMax] <> "\[Ellipsis]", str];

SetDirectory[currentDirectory];
joinedFiles = FileNameJoin[{currentDirectory, #}] & /@ FileNames[];

perFile[file_] := If[DirectoryQ[file],
FileNameTake[file] @@ readDir[file, level - 1],
ellipsize[FileNameTake[file]]];

perFile /@ joinedFiles
];

treeDir[dir_] := TreeForm[dir @@ readDir[dir, 5]];

treeDir["C:/blah/blah"]


This has a very poor display capacity if there are more than a certain number of files in a directory level.

It would need a lot of work to make the presentation reasonable in the general case. But this form of tree presentation of a file system also has a lot of potential. For example, you could build a graphical navigation system based on this (though not necessarily with TreeForm).

-
I posted an answer shamefully stealing your code. Hope you don't mind –  belisarius Jan 7 '13 at 11:57
@belisarius Absolutely not. Plus, a lot of my answers (such as this one) are more rough sketches than complete answers. I'm more interested in the "conversation," so to speak. :) –  amr Jan 7 '13 at 20:19

The following is a slight modification to @amr's code.

It shows a directory tree using TreeForm[], with a button at each vertex. When the button is pressed, it opens a dialog with the list of the files contained in that directory.

ellipsizeMax = 8;
ellipsize[str_] :=
If[StringLength[str] > ellipsizeMax,
StringTake[str, ellipsizeMax] <> "\[Ellipsis]", str];

Module[{joinedFiles, perFile}, SetDirectory[currentDirectory];
joinedFiles = FileNameJoin[{currentDirectory, #}] & /@ FileNames[];
perFile[file_] :=
If[DirectoryQ[file], file @@ readDir[file, level - 1],
Sequence @@ {}]; perFile /@ joinedFiles];

treeDir[dir_] := Module[{k},
VertexRenderingFunction ->
(Inset[Button[#2,
If[(k = FileNames["*.*", #2]) == {},
CreateDialog["No Files", WindowTitle -> #2],
CreateDialog[k, WindowTitle -> #2]]], #1] &)]]

treeDir["C:\\ff2"]


-

Here is the code required to implement Hypnotoad's solution (see comment to the question). I've copied Leonid's code over from its original thread.

The one problem I had with this solution was that FileNames["*", {"*"}, ∞] doesn't include empty directories. I replaced it with FileNames["*", Directory[], ∞], which solves that. But Directory[] is an absolute path so all those folders leading up to your current folder will be shown in the graph. I don't know how to solve that, one would have to find a replacement to {"*"} which includes directories but at the same time produces relative paths.

ClearAll[makeTree];
makeTree[wrds : {__String}] := makeTree[StringSplit[wrds, "/"]];
makeTree[wrds_ /; MemberQ[wrds, {}]] :=
Prepend[makeTree[DeleteCases[wrds, {}]], {} -> {}];
makeTree[wrds_] :=
Reap[If[# =!= {}, Sow[Rest[#], First@#]] & /@
wrds, _, #1 -> makeTree[#2] &][[2]]

ClearAll[getSubTree];
getSubTree[word_String, tree_] :=
Fold[#2 /. #1 &, tree, Characters[word]]

ClearAll[inTreeQ];
inTreeQ[word_String, tree_] :=
MemberQ[getSubTree[word, tree], {} -> {}]

ClearAll[getWords];
getWords[start_String, tree_] :=
Module[{wordStack = {}, charStack = {}, words},
words[{} -> {}] := wordStack = {wordStack, StringJoin[charStack]};
words[sl_ -> ll_List] := Module[{}, charStack = {charStack, sl};
words /@ ll;
charStack = First@charStack;];
words[First@
Fold[{#2 -> #1} &, getSubTree[start, tree],
Reverse@Characters[start]]];
ClearAll[words];
Flatten@wordStack];
SetDirectory["~/dirtest"];

TreeForm[
DeleteCases[
makeTree@Select[
FileNames["*", Directory[], \[Infinity]], DirectoryQ
], {} -> {}, {0, Infinity}] //. {Rule[a_, {}] :> a,
Rule[b_, c_] :> Apply[b, c]},
VertexRenderingFunction -> (Style[Text[#2, #1], 14,
Background -> White] &)
]

-