如何从Kotlin的资源中读取文本文件?


94

我想在Kotlin中编写Spek测试。测试应从文件src/test/resources夹中读取HTML文件。怎么做?

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

Answers:


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

30
对我来说,这行不通,我不得不将其更改为this::class.java.classLoader.getResource("/html/file.html").readText()
pavlos163

4
对我来说,这两个选项都在Android应用程序中起作用(请注意/其中一个中的多余内容,而另一个必须删除):this::class.java.getResource("/html/file.html").readText()this::class.java.classLoader.getResource("html/file.html").‌​readText()
Franco

19
val fileContent = javaClass.getResource("/html/file.html").readText()做的工作更短
Frank Neblung

28

另一个略有不同的解决方案:

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

扩展功能很好用!但是为什么在这里使用lambda函数呢?这对我来说没有多大意义。此外,该this部分对我不起作用。因此,我建议以下内容:fun String.asResource(): URL? = object {}.javaClass.getResource(this)
Qw3ry

我喜欢这种在声明文件的位置进行处理,然后处理该文件内容的方法。我猜个人喜好。this在上面的示例中,是指字符串对象。
jhodges

那是对扩展功能的严重滥用。加载文件与String类无关。

在这种情况下。我不会在全球范围内提供此功能,也不会在测试类之外使用它。我认为这里更多的是映射功能。
jhodges

25

不知道为什么这么难,但是我发现的最简单的方法(不必引用特定的类)是:

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

然后传入一个绝对URL,例如

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

{}必需的吗?为什么不只是javaClass.getResource(path).readText()呢?
andrewgazelka '19


3
上面方法的缺点是,它为每次资源访问都创建了一个新对象。将伪对象存储在函数外部会更好。
罗素·布里格斯

@RussellBriggs tbh我认为这没什么大不了的。如果您进行磁盘访问,则对象创建的性能并不是真正的问题!
Qw3ry

13

稍微不同的解决方案:

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

            var fileContent = ""

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

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

由于某种原因,这对我不起作用。仅显式调用该类有效。只是为别人加价。我认为与tornadofx有关
nmu

在中创建测试输入文件后/src/test/resourcesthis.javaClass.getResource("/<test input filename>")按预期工作。感谢您上面的解决方案。
jkwuc89

如果fileContent不是String并且我不会创建任何虚拟对象怎么办?
minizibi

1
在这里,在路径之前必须使用前导斜杠,而在Java中我通常会省略它。
cakraww


5

Kotlin + Spring方式:

@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

使用Google Guava库资源类

import com.google.common.io.Resources;

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

如果没有找到资源,Guave报告文件名是一件好事-更好地进行故障排除
Nishi

0

您可能会发现File类很有用:

import java.io.File

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

3
这个答案是误导的。那不会加载“资源”,而是直接从文件系统而不是类路径加载文件。组装完应用程序后,它将不再起作用,因为您将尝试引用不存在的文件,而不是从jar文件中加载它们。

@ben感谢您的评论。问题是关于在Kotlin Spek测试中从资源读取文件。
Krzysztof Ziomek

0

我更喜欢这样做:

fun getResourceText(path: String): String {
    return File(ClassLoader.getSystemResource(path).file).readText()
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.