# Learning julia and tidying hard drive

**URL:** <https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851>\
**Category:** New to Julia\
**Tags:** question, filesystem\
**Created:** [December 31, 2021, 4:17am UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851 "2021-12-31T04:17:20Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![nyloc](https://avatars.discourse-cdn.com/v4/letter/n/3ab097/32.png) [@nyloc](https://discourse.julialang.org/u/nyloc)\
**Post date:** [December 31, 2021, 4:17am UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/1 "2021-12-31T04:17:20Z")

</div>

I’ve just started learning Julia and would like some direction,  
This is some code I have created.

```julia
#!/home/col/programming/Julia/julia-1.7.1/bin/julia

# split vid and audio files into seperate directorys

new_dir_names = "audio_dir/" , "vids_dir/"
music_exts = ".flac" , ".mp3"

function process_dir(dir_name::String)
    cd(dir_name)
    list_of_files = readdir()
    for new_dir in new_dir_names
        if ! (isdir(new_dir))
            mkdir(new_dir)
        end
    end
    for loop_file in list_of_files
       if isfile(loop_file)
            file_first , file_ext = splitext(loop_file)
            file_ext = lowercase(file_ext)
            if file_ext in music_exts
                mv(loop_file,new_dir_names[1] * loop_file)
            end
       end
    end
    for del_dir in new_dir_names
        if isempty(readdir(del_dir))
            rm(del_dir)
        end
    end
    return
end

if length(ARGS) == 0
    start_dir = "."
else
    if isdir(ARGS[1])
        start_dir = ARGS[1]
    else
        println(ARGS[1] * " is not a directory")
        exit()
    end
end

process_dir(start_dir)

exit()

```

I would like to tidy up 20+ years of files starting with audio files.  
My questions are :- can I make this recurse into sub directories and how can I improve the code.  
Also probably need help using this forum.  
Thanks.  
Col.

---

<div class="post-metadata">

**Author:** ![melonedo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/melonedo/32/15503_2.png) [@melonedo](https://discourse.julialang.org/u/melonedo)\
**Post date:** [December 31, 2021, 4:33am UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/2 "2021-12-31T04:33:12Z")

</div>

About the format, code blocks are formatted with three backticks “```” instead of triple quote.

---

<div class="post-metadata">

**Author:** ![mmiller](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mmiller/32/20805_2.png) [@mmiller](https://discourse.julialang.org/u/mmiller)\
**Post date:** [December 31, 2021, 9:57am UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/3 "2021-12-31T09:57:14Z")

</div>

A nice function to go through all of a directory, including sub-folders, is [`walkdir`](https://docs.julialang.org/en/v1/base/file/#Base.Filesystem.walkdir)

Taken from the example in the link, it can be used like so to go through all directories:

```nohighlight
for (root, dirs, files) in walkdir(".")
    println("Directories in $root")
    for dir in dirs
        println(joinpath(root, dir)) # path to directories
    end
end

```

One small thing to neaten up the code without changing functionality, `readdir` can take a directory as an input so you’d don’t need the `cd`:

```nohighlight
cd(dir_name)
list_of_files = readdir()

```

becomes

```nohighlight
list_of_files = readdir(dir_name)

```

---

<div class="post-metadata">

**Author:** ![nyloc](https://avatars.discourse-cdn.com/v4/letter/n/3ab097/32.png) [@nyloc](https://discourse.julialang.org/u/nyloc)\
**Post date:** [December 31, 2021, 10:54am UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/4 "2021-12-31T10:54:22Z")

</div>

Thanks. I’ve looked at walkdir but don’t see how to create directories. move files and delete directories in the start directory and any sub directories. ie I want to keep files in their sub directories.

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [December 31, 2021, 11:28am UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/5 "2021-12-31T11:28:30Z")

</div>

You get the root path at every step of the walk, so you can use that to create the correct paths with `joinpath`, without changing your working directory to the current folder every time.

---

<div class="post-metadata">

**Author:** ![mmiller](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mmiller/32/20805_2.png) [@mmiller](https://discourse.julialang.org/u/mmiller)\
**Post date:** [December 31, 2021, 12:26pm UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/6 "2021-12-31T12:26:46Z")

</div>

> Thanks. I’ve looked at walkdir but don’t see how to create directories. move files and delete directories in the start directory and any sub directories. ie I want to keep files in their sub directories.

Would something like this work?

```julia
function process_dir(dir_name::String)
    for (root, dirs, files) in walkdir(dir_name)
        for dir in dirs
            process_single_dir(dir)
        end
    end
end

function process_single_dir(dir)
    for new_dir_name in new_dir_names
        new_dir = joinpath(dir, new_dir_name) # Use joinpath to create new folder in this directory
        if !isdir(new_dir) # removed spaces and brackets here
            mkdir(new_dir)
        end
    end
    list_of_files = readdir(dir)
    for loop_filename in list_of_files
        loop_filepath = joinpath(dir, loop_filename)
        if isfile(loop_filepath)
            file_first, file_ext = splitext(loop_filename) # removed space before comma here
            file_ext = lowercase(file_ext)
            if file_ext in music_exts
                mv(loop_filepath, joinpath(dir, new_dir_names[1], loop_filename))
            end
        end
    end
    for del_dir_name in new_dir_names
        del_dir = joinpath(dir, del_dir_name)
        if isempty(readdir(del_dir))
            rm(del_dir)
        end
    end
    return
end

```

I’ve used `joinpath` to ensure that everything stays relative to the current directory it’s in. Does it do what you want? By the way I haven’t tested it!

---

<div class="post-metadata">

**Author:** ![nyloc](https://avatars.discourse-cdn.com/v4/letter/n/3ab097/32.png) [@nyloc](https://discourse.julialang.org/u/nyloc)\
**Post date:** [December 31, 2021, 1:15pm UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/7 "2021-12-31T13:15:05Z")

</div>

tried testing that and got

[col@localhost Julia]$ ./julia-1.7.1/bin/julia test3.jl dummy\_dir/  
ERROR: LoadError: IOError: mkdir(“second\_level/audio\_dir/”; mode=0o777): no such file or directory (ENOENT)  
Stacktrace:  
[1] uv\_error  
@ ./libuv.jl:97 [inlined]  
[2] mkdir(path::String; mode::UInt16)  
@ Base.Filesystem ./file.jl:183  
[3] mkdir  
@ ./file.jl:176 [inlined]  
[4] process\_single\_dir(dir::String)  
@ Main ~/programming/Julia/test3.jl:17  
[5] process\_dir(dir\_name::String)  
@ Main ~/programming/Julia/test3.jl:8  
[6] top-level scope  
@ ~/programming/Julia/test3.jl:50  
in expression starting at /home/col/programming/Julia/test3.jl:50

---

<div class="post-metadata">

**Author:** ![nyloc](https://avatars.discourse-cdn.com/v4/letter/n/3ab097/32.png) [@nyloc](https://discourse.julialang.org/u/nyloc)\
**Post date:** [December 31, 2021, 1:23pm UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/8 "2021-12-31T13:23:09Z")

</div>

My testing directory contains  
[col@localhost Julia]$ ls -R dummy\_dir/  
dummy\_dir/:  
lena.jpg second\_level/

dummy\_dir/second\_level:  
Agatha.RaisinS04E01Kissing.Christmas.Goodbye720p.Web-Subs.srt third\_level/

dummy\_dir/second\_level/third\_level:  
ariel\_tylor\_s2-031.jpg mel\_martin.bmp

so presumably I need the higher level dir name in the path.

---

<div class="post-metadata">

**Author:** ![nyloc](https://avatars.discourse-cdn.com/v4/letter/n/3ab097/32.png) [@nyloc](https://discourse.julialang.org/u/nyloc)\
**Post date:** [December 31, 2021, 3:34pm UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/9 "2021-12-31T15:34:29Z")

</div>

I think I’ve found it.  
this works works but needs more testing

```julia
function process_dir(dir_name::String)
    cd(dir_name)
    files = readdir()
    mkdir("audio_dir")
    for loop_file in files
        if isdir(loop_file)
            process_dir(loop_file)
        end
        if isfile(loop_file)
            println("found file ",loop_file)
        end
    end
    return
end

```

---

<div class="post-metadata">

**Author:** ![mmiller](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mmiller/32/20805_2.png) [@mmiller](https://discourse.julialang.org/u/mmiller)\
**Post date:** [December 31, 2021, 5:48pm UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/10 "2021-12-31T17:48:01Z")

</div>

> ERROR: LoadError: IOError: mkdir(“second\_level/audio\_dir/”; mode=0o777): no such file or directory (ENOENT)

Ah yeah sorry, missed a `joinpath` here:

```julia
function process_dir(dir_name::String)
    for (root, dirs, files) in walkdir(dir_name)
        for dir in dirs
            process_single_dir(joinpath(root, dir)) # this one
        end
    end
end

```

But my solution would’ve needed modifying more as it assumed (incorrectly) that everything produced by `readdir()` was a file.

> I think I’ve found it.

Like the recursive solution, it’s elegant.

---

<div class="post-metadata">

**Author:** ![nyloc](https://avatars.discourse-cdn.com/v4/letter/n/3ab097/32.png) [@nyloc](https://discourse.julialang.org/u/nyloc)\
**Post date:** [December 31, 2021, 5:58pm UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/11 "2021-12-31T17:58:27Z")

</div>

I thought I tried that method a few days ago but now think I was silly enough to put the mkdir before the readdir and found the maximum recursion limit.

---

<div class="post-metadata">

**Author:** ![nyloc](https://avatars.discourse-cdn.com/v4/letter/n/3ab097/32.png) [@nyloc](https://discourse.julialang.org/u/nyloc)\
**Post date:** [December 31, 2021, 7:08pm UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/12 "2021-12-31T19:08:44Z")

</div>

Thank you. I try to write elegant code, it reads better and usually works better.

---

<div class="post-metadata">

**Author:** ![nyloc](https://avatars.discourse-cdn.com/v4/letter/n/3ab097/32.png) [@nyloc](https://discourse.julialang.org/u/nyloc)\
**Post date:** [January 1, 2022, 5:35pm UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/13 "2022-01-01T17:35:56Z")

</div>

I knew it was nqr, it needs a cd(“…”) immediately before the return statement.  
I get some interesting results however which I will probably put up another post about.  
I need to think about it for a while.

---

<div class="post-metadata">

**Author:** ![o314](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/o314/32/252_2.png) [@o314](https://discourse.julialang.org/u/o314)\
**Post date:** [January 1, 2022, 8:21pm UTC](https://discourse.julialang.org/t/learning-julia-and-tidying-hard-drive/73851/14 "2022-01-01T20:21:24Z")

</div>

You should have a look to [FilePath.jl](https://github.com/rofinn/FilePaths.jl) too.  
It will give you the ability to define path as vars and ‘/’ op them very intuitively  
Nearly every fs ops have been translated.

Not stdlib today, but it comes from a port of python pathlib that is
