Created
November 23, 2021 17:18
-
-
Save hiulit/772b8784436898fd7f942750ad99e33e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| func get_all_files(path: String, file_ext := "", files := []): | |
| var dir = Directory.new() | |
| if dir.open(path) == OK: | |
| dir.list_dir_begin(true, true) | |
| var file_name = dir.get_next() | |
| while file_name != "": | |
| if dir.current_is_dir(): | |
| files = get_all_files(dir.get_current_dir().plus_file(file_name), file_ext, files) | |
| else: | |
| if file_ext and file_name.get_extension() != file_ext: | |
| file_name = dir.get_next() | |
| continue | |
| files.append(file_name) | |
| file_name = dir.get_next() | |
| else: | |
| print("An error occurred when trying to access %s." % path) | |
| return files |
Author
Upgraded version for godot 4.x
func get_all_files(path: String, file_ext := "", files := []):
var dir = DirAccess.open(path)
if DirAccess.get_open_error() == OK:
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if dir.current_is_dir():
files = get_all_files(dir.get_current_dir() +"/"+ file_name, file_ext, files)
else:
if file_ext and file_name.get_extension() != file_ext:
file_name = dir.get_next()
continue
files.append(dir.get_current_dir() +"/"+ file_name)
file_name = dir.get_next()
else:
print("An error occurred when trying to access %s." % path)
return files
still works (godot4.2) + small improvement
## returns list of files at given path recursively
## [br]taken from - https://gist.github.com/hiulit/772b8784436898fd7f942750ad99e33e
static func get_all_files(path: String, file_ext := "", files : Array[String] = []) -> Array[String]:
var dir : = DirAccess.open(path)
if file_ext.begins_with("."): # get rid of starting dot if we used, for example ".tscn" instead of "tscn"
file_ext = file_ext.substr(1,file_ext.length()-1)
if DirAccess.get_open_error() == OK:
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if dir.current_is_dir():
# recursion
files = get_all_files(dir.get_current_dir() +"/"+ file_name, file_ext, files)
else:
if file_ext and file_name.get_extension() != file_ext:
file_name = dir.get_next()
continue
files.append(dir.get_current_dir() +"/"+ file_name)
file_name = dir.get_next()
else:
print("[get_all_files()] An error occurred when trying to access %s." % path)
return files
use like this:
var level_scenes := FileUtils.get_all_files(levels_folder_path, ".tscn")improvement
func get_files(path: String, ext: Variant = null) -> Array[String]:
var dir_access = DirAccess.open(path)
var files: Array[String] = []
for file_name in dir_access.get_files():
if ext == null || file_name.get_extension() == str(ext):
files.append(path.path_join(file_name))
for dir in dir_access.get_directories():
files.append_array(get_files(path.path_join(dir), ext))
return files
# get_files("res://")
# get_files("res://", "tscn")
Two variants, stack based, no recursion, documentation comments, extension comparison is case-insensitive
get_files("res://somefolder")
get_files("res://somefolder", [".tscn", ".tres"])With DirAccess.open
## Recursively gets the absolute path of all files in a directory with an optional extension filter.
## An empty filter array will return all files.
## The filter can optionally include the leading dot. The comparison is case-insensitive so [code]".TSCN"[/code] and [code]".tscn"[/code] are equivalent.
## This function uses [method DirAccess.open].
func get_files(path: String, filter: Array[String] = []) -> Array[String]:
# Godot get_extension() does not include the dot, so we remove it here for comparison
for i in filter.size():
while filter[i].begins_with("."):
filter[i] = filter[i].substr(1)
var found: Array[String] = []
var stack: Array[String] = [path]
while stack.size() > 0:
var current_path: String = stack.pop_back()
var dir := DirAccess.open(current_path)
if not dir:
push_warning("Could not open directory: \"%s\", %s" % [
error_string(DirAccess.get_open_error()),
current_path
])
continue
var err := dir.list_dir_begin()
if err != OK:
push_warning("Could not list directory: \"%s\", %s" % [
error_string(err),
current_path
])
continue
var file_name := dir.get_next()
while not file_name.is_empty():
if dir.current_is_dir():
stack.append(dir.get_current_dir().path_join(file_name))
# Fast, return everything
elif filter.is_empty():
found.append(dir.get_current_dir().path_join(file_name))
# Filter by extension
else:
var file_ext := file_name.get_extension()
for filter_ext in filter:
# Perfdorm a case-insensitive comparison, it's typically what you want
if file_ext.nocasecmp_to(filter_ext) == 0:
found.append(dir.get_current_dir().path_join(file_name))
break
# Get the next file or directory
file_name = dir.get_next()
return foundWith ResourceLoader.list_directory
## Recursively gets the absolute path of all files in a directory with an optional extension filter.
## An empty filter array will return all files.
## The filter can optionally include the leading dot. The comparison is case-insensitive so [code]".TSCN"[/code] and [code]".tscn"[/code] are equivalent.
## This function uses [method ResourceLoader.list_directory].
func get_resource_files(path: String, filter: Array[String] = []) -> Array[String]:
# Godot get_extension() does not include the dot, so we remove it here for comparison
for i in filter.size():
while filter[i].begins_with("."):
filter[i] = filter[i].substr(1)
var found: Array[String] = []
var stack: Array[String] = [path]
while stack.size() > 0:
var current_path: String = stack.pop_back()
for res_path in ResourceLoader.list_directory(current_path):
if res_path.ends_with("/"):
stack.append(current_path.path_join(res_path))
# Fast, return everything
elif filter.is_empty():
found.append(current_path.path_join(res_path))
# Filter by extension
else:
var file_ext := res_path.get_extension()
for filter_ext in filter:
# Perfdorm a case-insensitive comparison, it's typically what you want
if file_ext.nocasecmp_to(filter_ext) == 0:
found.append(current_path.path_join(res_path))
break
return foundSome additional notes, once you iterate over a directory, the next iteration will be faster as the OS (really pretty much any OS) cache the filesystem for subsequential access, very noticeable when you are iterating over a large asset folder or an external/virtual drive.
There is a glob match implementation in Godot that would filter "*.png", it is not used here.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you want the full path of the file instead of just the name, change:
Line 17
for