Let’s start small with an initial definition of printCatalogTree
.
function printCatalogTree(path::Str, pad::Str)
newPad::Str = pad * " "
for name in readdir(path)
newPath::Str = joinpath(path, name)
if isfile(newPath)
println(newPad, name)
else
println(newPad, name, "/")
printCatalogTree(newPath, newPad)
end
end
return nothing
end
function printCatalogTree(path::Str)
println(path, "/")
printCatalogTree(path, "")
return nothing
end
The function is rather simple. We walk through every entry (for name
) in the examined directory (path
). As we go name
is converted to newPath
which will be examined in a moment. If newPath
is a file (isfile
) we just print it, otherwise (else
) it is a directory and we print it with "/"
to make it stand out. Moreover we go inside of it with printCatalogTree
(recursive call) to print its contents. For every nesting of printCatalogTree
we update the padding newPad
by increasing the indentation with * " "
. We conclude with another version of printCatalogTree
, the method will make the function’s invocation slightly easier and will add a header line for us (println(path, "/")
) that will display the root directory (path
).
Let’s see how it works (remember to create catalog_x
with its contents first).
printCatalogTree(joinpath(homedir(), "Desktop", "catalog_x"))
/home/user_name/Desktop/catalog_x/
catalog_y/
catalog_z/
file_z.txt
file_y.txt
file_x.txt
It looks quite alright. Time to replace the spaces on the left with some guideways that we may follow with our eyes.
function printCatalogTree(path::Str, pad::Str)
newPad::Str = pad * "---"
for name in readdir(path)
newPath::Str = joinpath(path, name)
if isfile(newPath)
println(newPad, name)
else
println(newPad, name, "/")
printCatalogTree(newPath, pad * " |")
end
end
return nothing
end
function printCatalogTree(path::Str)
println(path, "/")
printCatalogTree(path, "|")
return nothing
end
To that end we changed the pad
s. We begin with the first column on the left that should start with the pipe character (printCatalogTree(path, "|")
). Each line containing a file or directory should continue with hyphens “—” (newPad::Str = pad * "---"
), whereas a nested directory and its contents should be indented and start with the pipe character as well (printCatalogTree(newPath, pad * " |")
). Let’s see did it work as intended.
printCatalogTree(joinpath(homedir(), "Desktop", "catalog_x"))
/home/user_name/Desktop/catalog_x/
|---catalog_y/
| |---catalog_z/
| | |---file_z.txt
| |---file_y.txt
|---file_x.txt
Not bad at all. Time to add a summary line.
function printCatalogTree!(path::Str, pad::Str, count::Dict{Str, Int})
newPad::Str = pad * "---"
for name in readdir(path)
newPath::Str = joinpath(path, name)
if isfile(newPath)
println(newPad, name)
count["nFiles"] += 1
else
println(newPad, name, "/")
count["nDirs"] += 1
printCatalogTree!(newPath, pad * " |", count)
end
end
return nothing
end
function printCatalogTree(path::Str)
println(path, "/")
count::Dict{Str, Int}= Dict("nDirs" => 0, "nFiles" => 0)
printCatalogTree!(path, "|", count)
print("\n", count["nDirs"], " directories, ", count["nFiles"], " files")
return nothing
end
The necessary data will be collected in a dictionary (count
). It has two keys: nDirs
and nFiles
for the number of directories and files in the tree, respectively. Remember that in Julia dictionaries are passed by reference so any modification you make to them inside of a function will be visible outside. For that purpose count
is defined in the outer printCatalogTree
, whereas the inner printCatalogTree!
got exclamation point per Julia’s convention to mark a function that modifies its arguments. Anyway, the count
dictionary is updated for every file (count["nFiles"] += 1
) and directory (count["nDirs"] += 1
) encountered and a summary line is added at the very bottom of the output (print("\n", count["nDirs"], " directories, ", count["nFiles"], " files")
). Let’s see how it works on a few examples (feel free to recreate mock directory structures as seen here).
First, a simple, already familiar to us, case.
printCatalogTree(joinpath(homedir(), "Desktop", "catalog_x"))
/home/user_name/Desktop/catalog_x/
|---catalog_y/
| |---catalog_z/
| | |---file_z.txt
| |---file_y.txt
|---file_x.txt
2 directories, 3 files
Now, a bit more convoluted tree.
printCatalogTree(joinpath(homedir(), "Desktop", "catalog_a"))
/home/user_name/Desktop/catalog_a/
|---catalog_b/
| |---catalog_d/
| | |---file_d.txt
| |---file_b1.txt
| |---file_b2.txt
|---catalog_c/
| |---catalog_e/
| | |---file_e.txt
| |---catalog_f/
| | |---file_f1.txt
| | |---file_f2.txt
| | |---file_f3.txt
| | |---file_f4.txt
|---file_a.txt
5 directories, 9 files
And an empty directory.
printCatalogTree(joinpath(homedir(), "Desktop", "catalog_zzz"))
/home/user_name/Desktop/catalog_zzz/
0 directories, 0 files
OK, that’s it. Another tiny utility under our belts.