Como ler um arquivo de texto de recursos em Kotlin?


94

Quero escrever um teste Spek em Kotlin. O teste deve ler um arquivo HTML da src/test/resourcespasta. Como fazer isso?

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

Respostas:


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

30
Para mim, isso não funcionou, tive que mudar parathis::class.java.classLoader.getResource("/html/file.html").readText()
— pavlos163 de

4
Para mim, ambas as opções funcionaram em um aplicativo Android (note o extra /em um deles, que deve ser removido no outro): 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()
— torna

28

outra solução ligeiramente diferente:

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

Bom uso de uma função de extensão! Mas por que você usa uma função lambda aqui? Isso não faz muito sentido para mim. Além disso, a thisparte não funcionou para mim. Portanto, eu recomendo o seguinte:fun String.asResource(): URL? = object {}.javaClass.getResource(this)
— Qw3ry

Gosto desse método de trabalhar nele, em que você declara o arquivo e, em seguida, trabalha no conteúdo desse arquivo. Preferência pessoal, eu acho. thisno exemplo acima se refere ao objeto string.
— jhodges

isso é um abuso terrível da função de extensão. Carregar arquivos não é uma preocupação da classe String.
— Ben

é neste contexto. Eu não disponibilizaria isso globalmente ou usaria fora das aulas de teste. Eu considero mais uma função de mapeamento aqui.
— jhodges

25

Não tenho ideia de por que isso é tão difícil, mas a maneira mais simples que encontrei (sem precisar me referir a uma classe em particular) é:

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

E então passar um URL absoluto, por exemplo

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

é {}necessário? Por que não apenas javaClass.getResource(path).readText()?
— andrewgazelka

1
javaClass deve ser chamado em um objeto de acordo com os documentos kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html Se funcionar sem, então vá para sua vida :)
— Russell Briggs

3
Uma desvantagem do método acima é que ele cria um novo objeto para cada acesso a recursos. Seria melhor armazenar o objeto fictício fora da função.
— Russell Briggs

@RussellBriggs tbh Não acho que isso importe muito. O desempenho da criação de um objeto não é realmente um problema se você acessar o disco!
— Qw3ry

13

Uma solução ligeiramente diferente:

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

            var fileContent = ""

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

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

Por algum motivo, isso não funcionou para mim. Apenas chamar explicitamente a classe funcionou. Apenas adicionando para outros. Acho que tem algo a ver com tornadofx
— nmu

Depois de criar um arquivo de entrada de teste no /src/test/resources, this.javaClass.getResource("/<test input filename>")funcionou conforme o esperado. Obrigado pela solução acima.
— jkwuc89

o que fazer, se fileContent não for String e eu não vou criar nenhum objeto fictício?
— minizibi

1
A barra inicial antes do caminho parece obrigatória aqui, enquanto em Java eu ​​geralmente a omito.
— cakraww

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

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

4

Usando a classe de recursos da biblioteca do Google Guava :

import com.google.common.io.Resources;

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

é bom que Guave informe um nome de arquivo se o recurso não for encontrado - muito melhor para solucionar problemas
— Nishi

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

0

Você pode achar a classe File útil:

import java.io.File

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

3
Essa resposta é enganosa. Isso não carrega um "recurso", mas carrega o arquivo diretamente do sistema de arquivos, ao invés do classpath. Não funcionará mais depois que o aplicativo for montado, pois você tentará se referir a arquivos não existentes, em vez de carregá-los do arquivo jar.
— Ben

@ben Obrigado pelo seu comentário. A questão era sobre como ler o arquivo do recurso no teste kotlin Spek.
— Krzysztof Ziomek

0

É assim que prefiro fazer:

fun getResourceText(path: String): String {
    return File(ClassLoader.getSystemResource(path).file).readText()
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.