+8 votes

Indeed.

asked Jun 12, 2016 in Engine by mateusak (1,074 points)

4 Answers

+18 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
answered Jun 12, 2016 by volzhs (9,483 points)
selected Jun 12, 2016 by mateusak

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.

+3 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()
answered Dec 21, 2019 by anachronost (20 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
answered May 2 by Poobslag (68 points)
0 votes

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
answered Aug 21 by ST4153 (14 points)
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.