2
$\begingroup$

Is there mkdirs() (make directory structure) equivalent in Mathematica? I want to specify something like this : dir1/dir2/dirn and I want Mathematica to create the directory structure dir1/dir2/dirn

$\endgroup$
  • 4
    $\begingroup$ CreateDirectory? $\endgroup$ – Yves Klett Jun 18 '14 at 12:00
  • 2
    $\begingroup$ CreateDirectory[FileNameJoin[{"this", "that", "other"}]] is an OS-independent way of creating a directory structure rooted in in the current directory. Evaluate ?*Directory* to discover what sort of things Mathematica can do with directories. $\endgroup$ – Stephen Luttrell Jun 18 '14 at 14:38
3
$\begingroup$

If you are on a Unix based OS you can use mkdir -p with Run:

Run["mkdir -p ~/Projects/" <> 
  StringJoin @@ (ToString@StringForm["folder``/", #] & /@ Range@5)]

Then running du ~/Projects will show:

~/Projects/folder1/folder2/folder3/folder4/folder5

If you are on Windows there should be the equivalent, I just don't know whether you need the -p or not.


Or as Yves Klett said:

CreateDirectory["~/Projects/" <> 
  StringJoin @@ (ToString@StringForm["folder``/", #] & /@ Range@5)]
$\endgroup$
4
$\begingroup$

Arguably, there is something better than mkdirs().

Some strings machinery first (nothing interesting):

spaceRiffledString = Composition[StringJoin, Riffle[Flatten@{##}, " "]&];

prefixStringViaSpace@s_String := spaceRiffledString@{s, #1}&

Directory creation handler:

createDirIfPossible =
Block[{CreateDirectory},
If[DirectoryQ@#,
Sequence @@ Transpose @
{ prefixStringViaSpace@"Directory" /@
  { "exists" ,     "created"     }
, {    #     , CreateDirectory@# } } // Evaluate]]&;

(An obsessive nod to D.R.Y. on my side.)

Map Mathematica native tree structure to file system:

createDirTree[address___, dir_String@subDirs___] :=
Map[createDirTree[address, dir, #]&, dir@subDirs, Heads -> True]

createDirTree[address___, _?AtomQ] :=
createDirIfPossible@FileNameJoin@{address}

Directories are represented as "dirName"[], and "fileName" without empty sublist is reserved for files. It's tedious to type [] when we know we need a pure directory tree so let's add a converter for convenience:

openAtoms = Replace[#, a_?AtomQ :> a[], {1, \[Infinity]}]&;

Error-checking for trees (not a perfect one, though):

stringTreeQ@expr_ :=
MatchQ[
  Replace[
    Cases[expr, _?AtomQ|_?AtomQ[]
    , {0, \[Infinity]}, Heads -> True]
  , s_String[] :> s, {1}]
, {__String}]

Finally,

Options@CreateDirectoryTree = {"Output Form" -> OpenerView};

CreateDirectoryTree[ tree_?stringTreeQ
                   , root:_String:$HomeDirectory
                   , OptionsPattern[]] :=
createDirTree@openAtoms@root@tree //.
If[OptionValue@"Output Form" === OpenerView
,  { {msg_String, addr_String}[] :> msg <> ": " <> addr
   , {msg_String, addr_String}@sub__ :>
     OpenerView[{{msg, addr}[], Column@{sub}}, False]}
,  {}]

(The //. … part is merely pretty printing.)

Try it:

CreateDirectoryTree @
"example"[
  "Beatles"[
    "Harrison"@"George",
    "Lennon",
    "McCartney",
    "Starr"],
  "Spam"@"Eggs"@"Cheese shop"]

If some directories exist, it doesn't produce errors, merely messages.

It doesn't take much effort to additionally parse the result with Button's to enrich it with immediate links to corresponding directories.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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