Як прочитати текстовий файл із ресурсів у Kotlin?


94

Я хочу написати тест Spek у Котліні. Тест повинен прочитати файл HTML з src/test/resourcesпапки. Як це зробити?

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

Відповіді:


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()
Франко

19
val fileContent = javaClass.getResource("/html/file.html").readText()робить роботу ще коротшою
Френк Неблунг

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

Приємного використання функції розширення! Але чому ви використовуєте лямбда-функцію тут? Для мене це не має особливого сенсу. Крім того, thisчастина не працювала для мене. Тому я рекомендую наступне:fun String.asResource(): URL? = object {}.javaClass.getResource(this)
Qw3ry

Мені подобається такий метод роботи над ним, де ви оголошуєте файл, а потім працюєте над вмістом цього файлу. Я вважаю, особисті переваги. thisу наведеному вище прикладі посилається на рядовий об'єкт.
jhodges

це страшне зловживання функцією розширення. Завантаження файлів не стосується класу String.
Бен

саме в цьому контексті. я не став би робити це глобально доступним або використовувати його поза тестовими класами. Я вважаю це більше функцією відображення тут.
Джоджес,

25

Не знаю, чому це так важко, але найпростіший спосіб, який я знайшов (без необхідності посилатися на певний клас):

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

А потім передаючи абсолютну URL-адресу, наприклад

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

це {}потрібно? Чому не просто javaClass.getResource(path).readText()?
andrewgazelka

1
javaClass потрібно викликати на об'єкт відповідно до документів kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html Якщо це працює без цього, переходьте до життя :)
Рассел Бріггс,

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
НММ

Після створення тестового вхідного файлу в /src/test/resources, this.javaClass.getResource("/<test input filename>")працював належним чином. Дякую за рішення вище.
jkwuc89

що робити, якщо fileContent не є рядком, і я не буду створювати фіктивний об'єкт?
minizibi

1
провідна коса риса перед шляхом тут здається обов'язковою, тоді як на Java я це зазвичай опускаю.
cakraww


5

Котлін + весняний спосіб:

@Autowired
private lateinit var resourceLoader: ResourceLoader

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


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.
Кшиштоф Зіомек

0

Я вважаю за краще це робити:

fun getResourceText(path: String): String {
    return File(ClassLoader.getSystemResource(path).file).readText()
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.