Michael
Michael

Reputation: 1134

Kotlin: get list of all files in resource folder

Is there a way to get list of all files in "resources" folder in Kotlin?

I can read specific file as

Application::class.java.getResourceAsStream("/folder/filename.ext")

But sometimes I just want to extract everything from folder "folder" to an external directory.

Upvotes: 14

Views: 32353

Answers (5)

GP K
GP K

Reputation: 11

Maybe you can try like the one below

fun getAllFiles(name: String) {
    val files = Base64Util::class.java.classLoader.getResources(name)
    val directoryPath = files.asIterator().next().path
    print("directoryPath - $directoryPath")
    val directory = File(directoryPath)
    if (directory.isDirectory) {
        directory.listFiles()?.forEach {
            println("File - ${it.absolutePath}")
        }
    }
}

Upvotes: 0

David Soroko
David Soroko

Reputation: 9106

The task has two distinct parts:

  1. Obtain a file that represents the resource directory
  2. Traverse the directory

For 1 you can use Java's getResource:

val dir = File( object {}.javaClass.getResource(directoryPath).file )

For 2 you can use Kotlin's File.walk extension function that returns a sequence of files you can process, e.g:

dir.walk().forEach { f ->
    if(f.isFile) {
        println("file ${f.name}")
    } else {
        println("dir ${f.name}")
    }
}

Put together you may end up with the following code:

fun onEachResource(path: String, action: (File) -> Unit) {

    fun resource2file(path: String): File {
        val resourceURL = object {}.javaClass.getResource(path)
        return File(checkNotNull(resourceURL, { "Path not found: '$path'" }).file)
    }

    with(resource2file(path)) {
        this.walk().forEach { f -> action(f) }
    }
}

so that if you have resources/nested direcory, you can:

fun main() {
    
    val print = { f: File ->
        when (f.isFile) {
            true -> println("[F] ${f.absolutePath}")
            false -> println("[D] ${f.absolutePath}")
        }
    }
    
    onEachResource("/nested", print)
}

Upvotes: 8

Vadzim
Vadzim

Reputation: 26210

Here is a solution to iterate over JAR-packed resources on JVM:

fun iterateResources(resourceDir: String) {
    val resource = MethodHandles.lookup().lookupClass().classLoader.getResource(resourceDir)
        ?: error("Resource $resourceDir was not found")
    FileSystems.newFileSystem(resource.toURI(), emptyMap<String, String>()).use { fs ->
        Files.walk(fs.getPath(resourceDir))
            .filter { it.extension == "ttf" }
            .forEach { file -> println(file.toUri().toString()) }
    }
}

Upvotes: 2

vivek86
vivek86

Reputation: 753

As I struggled with the same issue and couldn't find a concrete answer, so I had to write one myself.

Here is my solution:

fun getAllFilesInResources()
{
    val projectDirAbsolutePath = Paths.get("").toAbsolutePath().toString()
    val resourcesPath = Paths.get(projectDirAbsolutePath, "/src/main/resources")
    val paths = Files.walk(resourcesPath)
                    .filter { item -> Files.isRegularFile(item) }
                    .filter { item -> item.toString().endsWith(".txt") }
                    .forEach { item -> println("filename: $item") }
}

Here I have parsed through all the files in the /src/main/resources folder and then filtered only the regular files (no directories included) and then filtered for the text files within the resources directory.

The output is a list of all the absolute file paths with the extension .txt in the resources folder. Now you can use these paths to copy the files to an external folder.

Upvotes: 15

Zoe - Save the data dump
Zoe - Save the data dump

Reputation: 28288

There are no methods for it (i.e. Application::class.java.listFilesInDirectory("/folder/")), but you can create your own system to list the files in a directory:

@Throws(IOException::class)
fun getResourceFiles(path: String): List<String> = getResourceAsStream(path).use{
    return if(it == null) emptyList()
    else BufferedReader(InputStreamReader(it)).readLines()
}

private fun getResourceAsStream(resource: String): InputStream? = 
        Thread.currentThread().contextClassLoader.getResourceAsStream(resource) 
                ?: resource::class.java.getResourceAsStream(resource)

Then just call getResourceFiles("/folder/") and you'll get a list of files in the folder, assuming it's in the classpath.

This works because Kotlin has an extension function that reads lines into a List of Strings. The declaration is:

/**
 * Reads this reader content as a list of lines.
 *
 * Do not use this function for huge files.
 */
public fun Reader.readLines(): List<String> {
    val result = arrayListOf<String>()
    forEachLine { result.add(it) }
    return result
}

Upvotes: 5

Related Questions