Comment lire un fichier texte à partir de ressources dans Kotlin?

94

Je veux écrire un test Spek à Kotlin. Le test doit lire un fichier HTML à partir du src/test/resourcesdossier. Comment faire?

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
la source

Réponses:

111
val fileContent = MySpec::class.java.getResource("/html/file.html").readText()
JB Nizet
la source
30
Pour moi, cela n'a pas fonctionné, j'ai dû le changer enthis::class.java.classLoader.getResource("/html/file.html").readText()
pavlos163
4
Pour moi, ces deux options fonctionnaient dans une application Android (notez le supplément /dans l'une d'elles, qui doit être supprimé dans l'autre): this::class.java.getResource("/html/file.html").readText()etthis::class.java.classLoader.getResource("html/file.html").‌​readText()
Franco
19
val fileContent = javaClass.getResource("/html/file.html").readText()fait le travail encore plus court
Frank Neblung
28

une autre solution légèrement différente:

@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
la source
Bonne utilisation d'une fonction d'extension! Mais pourquoi utilisez-vous une fonction lambda ici? Cela n'a pas beaucoup de sens pour moi. De plus, la thispièce n'a pas fonctionné pour moi. Je recommande donc ce qui suit:fun String.asResource(): URL? = object {}.javaClass.getResource(this)
Qw3ry
J'aime cette méthode de travail où vous déclarez le fichier, puis travaillez sur le contenu de ce fichier. Préférence personnelle je suppose. thisdans l'exemple ci-dessus fait référence à l'objet string.
jhodges
c'est un terrible abus de la fonction d'extension. Le chargement de fichiers n'est pas une préoccupation de la classe String.
Ben le
c'est dans ce contexte. Je ne le rendrais pas disponible dans le monde entier ou ne l'utiliserais pas en dehors des classes de test. Je le considère plus comme une fonction de cartographie ici.
jhodges
25

Je ne sais pas pourquoi c'est si difficile, mais le moyen le plus simple que j'ai trouvé (sans avoir à faire référence à une classe particulière) est:

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

Et puis en passant une URL absolue, par exemple

val html = getResourceAsText("/www/index.html")
Russell Briggs
la source
est {}nécessaire? Pourquoi pas juste javaClass.getResource(path).readText()?
andrewgazelka
1
javaClass doit être appelé sur un objet selon la documentation kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html Si cela fonctionne sans alors allez-y pour votre vie :)
Russell Briggs
3
Un inconvénient de la méthode ci-dessus est qu'elle crée un nouvel objet pour chaque accès aux ressources. Il serait préférable de stocker l'objet factice en dehors de la fonction.
Russell Briggs
@RussellBriggs tbh Je ne pense pas que cela compte beaucoup. La performance de la création d'un objet n'est pas vraiment un problème si vous effectuez un accès disque!
Qw3ry
13

Une solution légèrement différente:

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
la source
Pour une raison quelconque, cela n'a pas fonctionné pour moi. Seulement appeler explicitement la classe a fonctionné. Juste ajouter pour les autres. Je pense que cela a quelque chose à voir avec tornadofx
nmu
Après avoir créé un fichier d'entrée de test dans /src/test/resources, a this.javaClass.getResource("/<test input filename>")fonctionné comme prévu. Merci pour la solution ci-dessus.
jkwuc89
que faire, si fileContent n'est pas String et que je ne créerai aucun objet factice?
minizibi
1
la barre oblique avant le chemin semble obligatoire ici, alors qu'en Java, je l'omets généralement.
cakraww
5
val fileContent = javaClass.getResource("/html/file.html").readText()
Jivimberg
la source
5

Voie Kotlin + Spring:

@Autowired
private lateinit var resourceLoader: ResourceLoader

fun load() {
    val html = resourceLoader.getResource("classpath:html/file.html").file
        .readText(charset = Charsets.UTF_8)
}
naXa
la source
5
private fun loadResource(file: String) = {}::class.java.getResource(file).readText()
Olaf
la source
4

Utilisation de la classe Ressources de la bibliothèque Google Guava :

import com.google.common.io.Resources;

val fileContent: String = Resources.getResource("/html/file.html").readText()
Lu55
la source
c'est bien que Guave signale un nom de fichier si la ressource n'est pas trouvée - beaucoup mieux pour le dépannage
Nishi
0

Vous pourriez trouver la classe File utile:

import java.io.File

fun main(args: Array<String>) {
  val content = File("src/main/resources/input.txt").readText()
  print(content)
} 
Krzysztof Ziomek
la source
3
Cette réponse est trompeuse. Cela ne charge pas une "ressource" mais charge le fichier directement à partir du système de fichiers, au lieu du chemin de classe. Cela ne fonctionnera plus une fois l'application assemblée, car vous essaierez de faire référence à des fichiers inexistants, au lieu de les charger à partir du fichier jar.
Ben le
@ben Merci pour votre commentaire. La question portait sur la lecture du fichier à partir de la ressource dans le test kotlin Spek.
Krzysztof Ziomek le
0

C'est comme ça que je préfère le faire:

fun getResourceText(path: String): String {
    return File(ClassLoader.getSystemResource(path).file).readText()
}
saidaspen
la source