Come leggere un file di testo dalle risorse in Kotlin?


94

Voglio scrivere un test Spek a Kotlin. Il test dovrebbe leggere un file HTML dalla src/test/resourcescartella. Come farlo?

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") {
                ...
            }
        }
    }
})

Risposte:


111
val fileContent = MySpec::class.java.getResource("/html/file.html").readText()

30
Per me questo non ha funzionato, ho dovuto cambiarlo inthis::class.java.classLoader.getResource("/html/file.html").readText()
pavlos163

4
Per me entrambe queste opzioni funzionavano in un'app Android (nota l'extra /in una di esse, che deve essere rimossa nell'altra): this::class.java.getResource("/html/file.html").readText()ethis::class.java.classLoader.getResource("html/file.html").‌​readText()
Franco

19
val fileContent = javaClass.getResource("/html/file.html").readText()fa il lavoro ancora più breve
Frank Neblung

28

un'altra soluzione leggermente diversa:

@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)
}

Buon utilizzo di una funzione di estensione! Ma perché usi una funzione lambda qui? Non ha molto senso per me. Inoltre, la thisparte non ha funzionato per me. Quindi consiglio quanto segue:fun String.asResource(): URL? = object {}.javaClass.getResource(this)
Qw3ry

Mi piace questo metodo di lavoro su di esso in cui dichiari il file, quindi lavori sul contenuto di quel file. Preferenza personale immagino. thisnell'esempio precedente si riferisce all'oggetto stringa.
jhodges

questo è un terribile abuso della funzione di estensione. Il caricamento dei file non è un problema della classe String.
Ben

è in questo contesto. Non lo renderei disponibile a livello globale né lo userei al di fuori delle classi di test. Lo considero più una funzione di mappatura qui.
jhodges

26

Non ho idea del perché sia ​​così difficile, ma il modo più semplice che ho trovato (senza dover fare riferimento a una classe particolare) è:

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

E poi passando un URL assoluto, ad es

val html = getResourceAsText("/www/index.html")

è {}richiesto? Perché non solo javaClass.getResource(path).readText()?
andrewgazelka

1
javaClass deve essere chiamato su un oggetto secondo i documenti kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html Se funziona senza allora vai per la tua vita :)
Russell Briggs

3
Uno svantaggio del metodo sopra è che crea un nuovo oggetto per ogni accesso alle risorse. Sarebbe meglio memorizzare l'oggetto fittizio al di fuori della funzione.
Russell Briggs

@RussellBriggs tbh Non penso che importi molto. Le prestazioni della creazione di un oggetto non sono davvero un problema se si accede al disco!
Qw3ry

13

Una soluzione leggermente diversa:

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

            var fileContent = ""

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

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

Per qualche motivo questo non ha funzionato per me. Solo la chiamata esplicita della classe ha funzionato. Aggiungendo solo per gli altri. Penso che abbia qualcosa a che fare con tornadofx
nmu

Dopo aver creato un file di input di prova in /src/test/resources, ha this.javaClass.getResource("/<test input filename>")funzionato come previsto. Grazie per la soluzione sopra.
jkwuc89

cosa fare, se fileContent non è String e non creerò alcun oggetto fittizio?
minizibi

1
la barra prima del percorso sembra obbligatoria qui, mentre in Java di solito la ometto.
cakraww

5
val fileContent = javaClass.getResource("/html/file.html").readText()

5

Kotlin + Spring way:

@Autowired
private lateinit var resourceLoader: ResourceLoader

fun load() {
    val html = resourceLoader.getResource("classpath:html/file.html").file
        .readText(charset = Charsets.UTF_8)
}

5
private fun loadResource(file: String) = {}::class.java.getResource(file).readText()

4

Utilizzo della classe delle risorse della libreria Google Guava :

import com.google.common.io.Resources;

val fileContent: String = Resources.getResource("/html/file.html").readText()

è bello che Guave riporti un nome di file se la risorsa non viene trovata - molto meglio per la risoluzione dei problemi
Nishi

0

Potresti trovare utile la classe File:

import java.io.File

fun main(args: Array<String>) {
  val content = File("src/main/resources/input.txt").readText()
  print(content)
} 

3
Questa risposta è fuorviante. Ciò non carica una "risorsa" ma carica il file direttamente dal file system, invece del classpath. Non funzionerà più dopo che l'applicazione è stata assemblata poiché proverai a fare riferimento a file inesistenti, invece di caricarli dal file jar.
Ben

@ben Grazie per il tuo commento. La domanda riguardava la lettura del file dalla risorsa nel test Spek di kotlin.
Krzysztof Ziomek

0

Questo è il modo in cui preferisco farlo:

fun getResourceText(path: String): String {
    return File(ClassLoader.getSystemResource(path).file).readText()
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.