Wie lese ich eine Textdatei aus Ressourcen in Kotlin?

94

Ich möchte einen Spek-Test in Kotlin schreiben. Der Test sollte eine HTML-Datei aus dem src/test/resourcesOrdner lesen . Wie es geht?

class MySpec : Spek({

    describe("blah blah") {

        given("blah blah") {

            var fileContent : String = ""

            beforeEachTest {
                // How to read the file file.html in src/test/resources/html
                fileContent = ...  
            }

            it("should blah blah") {
                ...
            }
        }
    }
})
Olaf
quelle

Antworten:

109
val fileContent = MySpec::class.java.getResource("/html/file.html").readText()
JB Nizet
quelle
30
Für mich hat das nicht funktioniert, ich musste es ändern inthis::class.java.classLoader.getResource("/html/file.html").readText()
pavlos163
4
Für mich funktionierten beide Optionen in einer Android-App (beachten Sie das Extra /in einer von ihnen, das in der anderen entfernt werden muss): this::class.java.getResource("/html/file.html").readText()undthis::class.java.classLoader.getResource("html/file.html").‌​readText()
Franco
19
val fileContent = javaClass.getResource("/html/file.html").readText()macht den Job noch kürzer
Frank Neblung
28

eine andere etwas andere Lösung:

@Test
fun basicTest() {
    "/html/file.html".asResource {
        // test on `it` here...
        println(it)
    }

}

fun String.asResource(work: (String) -> Unit) {
    val content = this.javaClass::class.java.getResource(this).readText()
    work(content)
}
jhodges
quelle
Gute Nutzung einer Erweiterungsfunktion! Aber warum benutzt du hier eine Lambda-Funktion? Das macht für mich nicht viel Sinn. Außerdem hat das thisTeil bei mir nicht funktioniert. Daher empfehle ich Folgendes:fun String.asResource(): URL? = object {}.javaClass.getResource(this)
Qw3ry
Ich mag diese Methode, wenn Sie die Datei deklarieren und dann den Inhalt dieser Datei bearbeiten. Persönliche Vorlieben, denke ich. thisim obigen Beispiel bezieht sich auf das String-Objekt.
jhodges
Das ist ein schrecklicher Missbrauch der Erweiterungsfunktion. Das Laden von Dateien ist kein Problem der String-Klasse.
Ben
es ist in diesem Zusammenhang. Ich würde dies nicht global verfügbar machen oder außerhalb von Testklassen verwenden. Ich halte es hier eher für eine Mapping-Funktion.
Jhodges
25

Keine Ahnung, warum das so schwierig ist, aber der einfachste Weg, den ich gefunden habe (ohne mich auf eine bestimmte Klasse beziehen zu müssen), ist:

fun getResourceAsText(path: String): String {
    return object {}.javaClass.getResource(path).readText()
}

Und dann eine absolute URL eingeben, z

val html = getResourceAsText("/www/index.html")
Russell Briggs
quelle
ist {}erforderlich? Warum nicht einfach javaClass.getResource(path).readText()?
Andrewgazelka
1
javaClass muss für ein Objekt gemäß den Dokumenten kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html aufgerufen werden. Wenn es ohne funktioniert, gehen Sie für Ihr Leben :)
Russell Briggs
3
Ein Nachteil der obigen Methode ist, dass für jeden Ressourcenzugriff ein neues Objekt erstellt wird. Es wäre besser, das Dummy-Objekt außerhalb der Funktion zu speichern.
Russell Briggs
@RussellBriggs tbh Ich denke nicht, dass das viel zählt. Die Leistung einer Objekterstellung ist kein wirkliches Problem, wenn Sie auf die Festplatte zugreifen!
Qw3ry
13

Eine etwas andere Lösung:

class MySpec : Spek({
    describe("blah blah") {
        given("blah blah") {

            var fileContent = ""

            beforeEachTest {
                html = this.javaClass.getResource("/html/file.html").readText()
            }

            it("should blah blah") {
                ...
            }
        }
    }
})
Olaf
quelle
Aus irgendeinem Grund hat das bei mir nicht funktioniert. Nur das explizite Aufrufen der Klasse hat funktioniert. Nur für andere hinzufügen. Ich denke, es hat etwas mit tornadofx zu tun
nmu
Nach dem Erstellen einer Testeingabedatei in /src/test/resources, this.javaClass.getResource("/<test input filename>")funktionierte wie erwartet. Danke für die obige Lösung.
jkwuc89
Was tun, wenn fileContent kein String ist und ich kein Dummy-Objekt erstellen werde?
Minizibi
1
Ein führender Schrägstrich vor dem Pfad scheint hier obligatorisch zu sein, während ich ihn in Java normalerweise weglasse.
Cakraww
5

Kotlin + Frühlingsweg:

@Autowired
private lateinit var resourceLoader: ResourceLoader

fun load() {
    val html = resourceLoader.getResource("classpath:html/file.html").file
        .readText(charset = Charsets.UTF_8)
}
naXa
quelle
4
val fileContent = javaClass.getResource("/html/file.html").readText()
Jivimberg
quelle
4

Verwenden der Ressourcenklasse der Google Guava-Bibliothek :

import com.google.common.io.Resources;

val fileContent: String = Resources.getResource("/html/file.html").readText()
Lu55
quelle
Es ist schön, dass Guave einen Dateinamen meldet, wenn keine Ressource gefunden wird - viel besser für die Fehlerbehebung
Nishi
3
private fun loadResource(file: String) = {}::class.java.getResource(file).readText()
Olaf
quelle
0

Die Datei-Klasse ist möglicherweise hilfreich:

import java.io.File

fun main(args: Array<String>) {
  val content = File("src/main/resources/input.txt").readText()
  print(content)
} 
Krzysztof Ziomek
quelle
2
Diese Antwort ist irreführend. Dadurch wird keine "Ressource" geladen, sondern eine Datei direkt aus dem Dateisystem anstelle des Klassenpfads. Nach dem Zusammenstellen der Anwendung funktioniert dies nicht mehr, da Sie versuchen, auf nicht vorhandene Dateien zu verweisen, anstatt sie aus der JAR-Datei zu laden.
Ben
@ben Danke für deinen Kommentar. Die Frage betraf das Lesen einer Datei aus einer Ressource im Kotlin Spek-Test.
Krzysztof Ziomek
0

So mache ich es lieber:

fun getResourceText(path: String): String {
    return File(ClassLoader.getSystemResource(path).file).readText()
}
sagteaspen
quelle