First off, a more compact form of filesInDir
:
fileTree[f_, d_] /; DirectoryQ[f] && d > 0 :=
FileNameTake[f] -> (fileTree[#, d - 1] & /@ FileNames[___, f])
fileTree[f_, _] := FileNameTake[f]
Example usage:
fileTree[$UserBaseDirectory, 2]
(* "Mathematica" -> {"ApplicationData" -> {"CCompilerDriver",
"DeviceFramework", "ImageAcquisition", "Parallel"},
"Applications" -> {}, "Autoload" -> {"PacletManager"},
"FrontEnd" -> {"init.m"}, "Kernel" -> {"init.m"}, "Licensing" -> {},
"Paclets" -> {"Configuration", "Repository", "Temporary"},
"SystemFiles" -> {"CharacterEncodings", "FrontEnd", "Java",
"Kernel", "LibraryResources", "SpellingDictionaries"}} *)
Personally I don't like the way that bottom-level directories are treated the same way as files (head String
instead of head Rule
). Here's an alternate method:
Clear[fileTree]
fileTree[f_, d_] /; DirectoryQ[f] :=
FileNameTake[f] -> If[d > 0, fileTree[#, d-1]& /@ FileNames[___, f], Missing["TooDeep"]]
fileTree[f_, _] := FileNameTake[f]
Example usage:
fileTree[$UserBaseDirectory, 2]
(* "Mathematica" -> {"ApplicationData" -> {"CCompilerDriver" ->
Missing["TooDeep"], "DeviceFramework" -> Missing["TooDeep"],
"ImageAcquisition" -> Missing["TooDeep"],
"Parallel" -> Missing["TooDeep"]}, "Applications" -> {},
"Autoload" -> {"PacletManager" -> Missing["TooDeep"]},
"FrontEnd" -> {"init.m"}, "Kernel" -> {"init.m"}, "Licensing" -> {},
"Paclets" -> {"Configuration" -> Missing["TooDeep"],
"Repository" -> Missing["TooDeep"],
"Temporary" -> Missing["TooDeep"]},
"SystemFiles" -> {"CharacterEncodings" -> Missing["TooDeep"],
"FrontEnd" -> Missing["TooDeep"], "Java" -> Missing["TooDeep"],
"Kernel" -> Missing["TooDeep"],
"LibraryResources" -> Missing["TooDeep"],
"SpellingDictionaries" -> Missing["TooDeep"]}} *)
You can replace Missing["TooDeep"]
with whatever you want, as long as it's not a List
.
To convert a tree (either form) to your list format:
treeToList[d_ -> _Missing] := {{d}}
treeToList[s_String] := {{s}}
treeToList[d_ -> l_] := Prepend[Prepend[d] /@ Join @@ (treeToList /@ l), {d}]
Example usage:
tree = fileTree[$UserBaseDirectory, 2];
treeToList[tree] // Column
(* {
{"Mathematica"},
{"Mathematica", "ApplicationData"},
{"Mathematica", "ApplicationData", "CCompilerDriver"},
{"Mathematica", "ApplicationData", "DeviceFramework"},
{"Mathematica", "ApplicationData", "ImageAcquisition"},
{"Mathematica", "ApplicationData", "Parallel"},
{"Mathematica", "Applications"},
{"Mathematica", "Autoload"},
{"Mathematica", "Autoload", "PacletManager"},
{"Mathematica", "FrontEnd"},
{"Mathematica", "FrontEnd", "init.m"},
{"Mathematica", "Kernel"},
{"Mathematica", "Kernel", "init.m"},
{"Mathematica", "Licensing"},
{"Mathematica", "Paclets"},
{"Mathematica", "Paclets", "Configuration"},
{"Mathematica", "Paclets", "Repository"},
{"Mathematica", "Paclets", "Temporary"},
{"Mathematica", "SystemFiles"},
{"Mathematica", "SystemFiles", "CharacterEncodings"},
{"Mathematica", "SystemFiles", "FrontEnd"},
{"Mathematica", "SystemFiles", "Java"},
{"Mathematica", "SystemFiles", "Kernel"},
{"Mathematica", "SystemFiles", "LibraryResources"},
{"Mathematica", "SystemFiles", "SpellingDictionaries"}
} *)
We can't get back to the full output of FileNameSplit /@ FileNames["*", $UserBaseDirectory, 2]
since the base path is lost when converting to a tree.
"Licensing" -> {}
in your output list. I assume this is OK (desired?) for directories but not files, correct? $\endgroup$FileDelete
,CopyFile
etc. $\endgroup$