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

Respostas:

110
val fileContent = MySpec::class.java.getResource("/html/file.html").readText()
JB Nizet
fonte
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)
}
Jhodges
fonte
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")
Russell Briggs
fonte
é {}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") {
                ...
            }
        }
    }
})
Olaf
fonte
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)
}
naXa
fonte
4
val fileContent = javaClass.getResource("/html/file.html").readText()
Jivimberg
fonte
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()
Lu55
fonte
é 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()
Olaf
fonte
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)
} 
Krzysztof Ziomek
fonte
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()
}
Saidaspen
fonte