Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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.

share|improve this question
    
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
1  
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
4  
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

3 Answers 3

up vote 5 down vote accepted

Here's a relatively straightforward "first version":

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

readDir[currentDirectory_, 0] := ellipsize[FileNameTake[currentDirectory]];
readDir[currentDirectory_, level_] := Module[{joinedFiles, perFile},
   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).

share|improve this answer
    
I posted an answer shamefully stealing your code. Hope you don't mind –  belisarius Jan 7 '13 at 11:57
1  
@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

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] &)
 ]
share|improve this answer

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];

readDir[currentDirectory_, 0] := ellipsize[FileNameTake[currentDirectory]];
readDir[currentDirectory_, level_] := 
  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}, 
                TreeForm[dir @@ readDir[dir, 5],
                     VertexRenderingFunction -> 
                         (Inset[Button[#2,
                                If[(k = FileNames["*.*", #2]) == {},
                                        CreateDialog["No Files", WindowTitle -> #2],
                                        CreateDialog[k, WindowTitle -> #2]]], #1] &)]]

treeDir["C:\\ff2"]

Mathematica graphics

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.