+8 votes

Indeed.

in Engine by (1,087 points)

5 Answers

+19 votes
Best answer
func list_files_in_directory(path):
    var files = []
    var dir = Directory.new()
    dir.open(path)
    dir.list_dir_begin()

    while true:
        var file = dir.get_next()
        if file == "":
            break
        elif not file.begins_with("."):
            files.append(file)

    dir.list_dir_end()

    return files
by (9,674 points)
selected by

I know this is an old question, but could you maybe provide some explanation to how this works, as that would be a lot more helpful than just a code to copy and paste.

func list_files_in_directory(path):
    var files = []
    var dir = Directory.new()
    dir.open(path)
    dir.list_dir_begin()

Create an array called "files", create a new Directory called "dir", you give to "dir" the path of the folder to open, probably something like "res://scenes", and you start to look for filenames with listdirbegin()

while true:
    var file = dir.get_next()
    if file == "":
        break
    elif not file.begins_with("."):
        files.append(file)

You get the next filename until you get to the end of the stream with (if file == ""), you go out of the loop with "break", elif (else if) the file does not start with a "." means the current file is not a directory (You can use file.currentisdir ( ) wich return true or false) you push the value in the end of the array files (to keep a track, no need to reopen a Directory after that, and in this case the author don't want the subpaths, just filenames)

dir.list_dir_end()

Close de stream of data (not needed in this case according to the godot doc)

return files

And this is not just a code to copy paste, but a code to understand, line by line, it is speaking for itself, usually you just have to read the godot doc to find what the different classes and functions are doing

I get ERRPARSEERROR with "dir.open("res://whatever")"

According to the documentation here, you no longer need to call list_dir_end() after get_next() returns the empty string, since it is called automatically.

At least as of Godot 3.1 Directory.list_dir_begin() takes in two optional parameters: skip_navigational and skip_hidden. If skipnavigational is true then "." and ".." (the current and parent directories, respectively) will be ignored and if skiphidden is true then whatever the OS considers a hidden file (file name starts with "." on *NIXes) will be ignored.

They both default to false, but setting them both to true would eliminate the need for the elif not file.begins_with("."): check in this example.

+6 votes

As I didn't find a complete solution that goes through the subdirectories while searching and writing this and came here, here goes:

Below is a complete solution for recursively getting all files and folders under a root folder.

Return all filenames and directories (with full filepaths) under root path.

func get_dir_contents(rootPath: String) -> Array:
    var files = []
    var directories = []
    var dir = Directory.new()

    if dir.open(rootPath) == OK:
        dir.list_dir_begin(true, false)
        _add_dir_contents(dir, files, directories)
    else:
        push_error("An error occurred when trying to access the path.")

    return [files, directories]

Recursively list and add all filenames and directories with full paths to their respective arrays.

func _add_dir_contents(dir: Directory, files: Array, directories: Array):
    var file_name = dir.get_next()

    while (file_name != ""):
        var path = dir.get_current_dir() + "/" + file_name

        if dir.current_is_dir():
            print("Found directory: %s" % path)
            var subDir = Directory.new()
            subDir.open(path)
            subDir.list_dir_begin(true, false)
            directories.append(path)
            _add_dir_contents(subDir, files, directories)
        else:
            print("Found file: %s" % path)
            files.append(path)

        file_name = dir.get_next()

    dir.list_dir_end()
by (26 points)
0 votes

In trying to solve this problem myself, I wrote a function which traverses a directory to find all PNG assets.

"""
Returns a list of all png files in the /assets directory.

Recursively traverses the assets directory searching for pngs. Any additional directories it discovers are appended to
a queue for later traversal.

Note: We search for '.png.import' files instead of searching for png files directly. This is because png files
  disappear when the project is exported.
"""
func _find_png_paths() -> Array:
  var png_paths := [] # accumulated png paths to return
  var dir_queue := ["res://assets"] # directories remaining to be traversed
  var dir: Directory # current directory being traversed

  var file: String # current file being examined
  while file or not dir_queue.empty():
    # continue looping until there are no files or directories left
    if file:
      # there is another file in this directory
      if dir.current_is_dir():
        # found a directory, append it to the queue.
        dir_queue.append("%s/%s" % [dir.get_current_dir(), file])
      elif file.ends_with(".png.import"):
        # found a .png.import file, append its corresponding png to our results
        png_paths.append("%s/%s" % [dir.get_current_dir(), file.get_basename()])
    else:
      # there are no more files in this directory
      if dir:
        # close the current directory
        dir.list_dir_end()

      if dir_queue.empty():
        # there are no more directories. terminate the loop
        break

      # there are more directories. open the next directory
      dir = Directory.new()
      dir.open(dir_queue.pop_front())
      dir.list_dir_begin(true, true)
    file = dir.get_next()

  return png_paths
by (93 points)
+1 vote

some optimizations to volzhs answer

func get_files(path):
    var files = []
    var dir = Directory.new()
    dir.open(path)
    dir.list_dir_begin(true)

    var file = dir.get_next()
    while file != '':
        files += [file]
        file = dir.get_next()

    return files
by (16 points)
0 votes

A slightly cleaner version for recursively getting files inside a directory. (Godot 3)

static func get_dir_files(path: String) -> PoolStringArray:
    var arr: PoolStringArray
    var dir := Directory.new()
    dir.open(path)

    if dir.file_exists(path):
        arr.append(path)

    else:
        dir.list_dir_begin(true,  true)
        while(true):
            var subpath := dir.get_next()
            if subpath.empty():
                break
            arr += get_dir_files(path.plus_file(subpath))

    return arr
by (248 points)

Sorry but this one's slow in speed tests compared to anachronost's answer which is about 22 times faster (that one's recursive too).

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.