Getting inconsistent error from walkdir

walkdir works for some directories and not others.

julia> file_list = readdir("dummy_dir/")
5-element Vector{String}:
 "0458899-1920x1080.jpg"
 "2nd_dir"
 "The Unbelievable Truth S01E01.mp3"
 "lena.jpg"
 "second_level"

julia> file_list = readdir("dummy_dir/second_level/")
3-element Vector{String}:
 "Everyman's Guide to Mornington Crescent-7kwmYFo927g.mp4"
 "s00e00 - Pilot - Hair, fo\$otball, cats, bees.mp3"
 "third_level"

julia> file_list = readdir("dummy_dir/2nd_dir/")
2-element Vector{String}:
 "144_RAAF_plane_list.txt"
 "3rd_dir"

julia> root, dirs, files = walkdir("dummy_dir/second_level/")
Channel{Tuple{String, Vector{String}, Vector{String}}}(0) (1 item available)

julia> root, dirs, files = walkdir("dummy_dir/2nd_dir/")
ERROR: BoundsError: attempt to access Channel{Tuple{String, Vector{String}, Vector{String}}} at index [3]
Stacktrace:
 [1] indexed_iterate(I::Channel{Tuple{String, Vector{String}, Vector{String}}}, i::Int64, state::Nothing)
   @ Base ./tuple.jl:98
 [2] top-level scope
   @ REPL[5]:1

julia> 

walkdir fails to open an existing directory, and what is is worse is, it works with one directory but not the other.
anyone know what is going on?
thanks.

The way you use the return value of walkdir is wrong: it doesn’t return a tuple of root, dirs and files. Instead it returns an iterator of such tuples. So with the line

root, dirs, files = walkdir("dummy_dir/second_level/")

you will have the first (root, dirs, files) of the iterator in a variable root, the second (root, dirs, files) in a variable dirs, and the third one in files. This is not what you want, and it fails the tree has less than 3 directories because in that case you cannot get 3 tuples from the iterator.

3 Likes

it doesn’t fail because of the number of directories, it doesn’t matter what order I call walkdirit still fails on the directory “2nd_dir” but not the directory “second_level”.

[col@localhost Julia]$ ./julia-1.7.1/bin/julia 
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.7.1 (2021-12-22)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> root, dirs, files = walkdir("dummy_dir/2nd_dir/")
ERROR: BoundsError: attempt to access Channel{Tuple{String, Vector{String}, Vector{String}}} at index [3]
Stacktrace:
 [1] indexed_iterate(I::Channel{Tuple{String, Vector{String}, Vector{String}}}, i::Int64, state::Nothing)
   @ Base ./tuple.jl:98
 [2] top-level scope
   @ REPL[1]:1

julia> root, dirs, files = walkdir("dummy_dir/second_level/")
Channel{Tuple{String, Vector{String}, Vector{String}}}(0) (1 item available)

julia> 

Please read again my previous answer. The problem is that

root, dirs, files = walkdir("dummy_dir/2nd_dir/")

wants to extract 3 values from the result of walkdir. The variable names are misleading here, what you are actually doing is clearer if you write

dir1, dir2, dir3 = walkdir("dummy_dir/2nd_dir/")

Obviously this does the same thing, but now the problem is clear: you cannot extract 3 directories from walkdir if the tree starting at 2nd_dir/ contains only two directories.

Instead you should iterate on the result of walkdir. For example with a loop:

for dir in walkdir("dummy_dir/2nd_dir/")
    ... # Use the dir tuple here, which contains 3 elements: rootpath, dirs and files
end

You can also use destructuring to extract the 3 elements of each dir directly in the loop definition:

for (rootpath, dirs, files) in walkdir("dummy_dir/2nd_dir/")
    ... # Use directly the values of rootpath, dirs and files
end
3 Likes

Sorry, you’re right I was using walkdir wrong.

Ok, result is an “iterator” and I can destruct it via a for loop.
But I am still lost. Is there e.g. a chance to figure out the number of levels of a directory tree?
Can I restrict the walkdir-function to a specific number of directory levels.
And then what does this additional Channel{} do to the Tuple{}
To figure out the number of levels of a directory tree you may count the occurrences of the
file separator char, which is different dependent on the current OS.
Below my attempt to count this letter in directory string (e.g. variable “root” in the proposed
for-loop in combination with “walkdir”:

# count depth / number of levels of a path
if Sys.iswindows()
    reg_path_separator = r"\\\\"
    s_dir = raw"C:\data\julia\scripts"
else
    reg_path_separator = r"/"
    s_dir = "/media/data/julia"
end
n_path_level = length(collect(eachmatch(reg_path_separator, s_dir; overlap=false)))