Learning julia and tidying hard drive

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

#!/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.

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

A nice function to go through all of a directory, including sub-folders, is walkdir

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

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:

cd(dir_name)
list_of_files = readdir()

becomes

list_of_files = readdir(dir_name)
3 Likes

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.

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.

1 Like

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?

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!

1 Like

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

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.

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

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

ERROR: LoadError: IOError: mkdir(“second_level/audio_dir/”; mode=0o777): no such file or directory (ENOENT)

Ah yeah sorry, missed a joinpath here:

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.

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.

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

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.

You should have a look to FilePath.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

1 Like