Bagaimana cara membaca file teks dari sumber daya di Kotlin?

97

Saya ingin menulis tes Spek di Kotlin. Tes harus membaca file HTML dari src/test/resourcesfolder. Bagaimana cara melakukannya?

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
sumber

Jawaban:

116
val fileContent = MySpec::class.java.getResource("/html/file.html").readText()
JB Nizet
sumber
30
Bagi saya ini tidak berhasil, saya harus mengubahnya menjadithis::class.java.classLoader.getResource("/html/file.html").readText()
pavlos163
4
Bagi saya, kedua opsi ini berfungsi di aplikasi Android (perhatikan tambahan /di salah satunya, yang harus dihapus di opsi lain): this::class.java.getResource("/html/file.html").readText()danthis::class.java.classLoader.getResource("html/file.html").‌​readText()
Franco
20
val fileContent = javaClass.getResource("/html/file.html").readText()melakukan pekerjaan lebih pendek lagi
Frank Neblung
1
Anehnya, saya selalu membutuhkan garis miring. Misalnya, jika file ada di direktori root resource, Anda masih harus merujuknya sebagai "/file.html"
Somaiah Kumbera
28

solusi lain yang sedikit berbeda:

@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
sumber
Penggunaan yang bagus dari fungsi ekstensi! Tetapi mengapa Anda menggunakan fungsi lambda di sini? Itu tidak masuk akal bagi saya. Selain itu, thisbagian itu tidak berhasil untuk saya. Karena itu saya merekomendasikan yang berikut ini:fun String.asResource(): URL? = object {}.javaClass.getResource(this)
Qw3ry
Saya suka metode mengerjakannya di mana Anda mendeklarasikan file, lalu mengerjakan konten file itu. Preferensi pribadi saya kira. thispada contoh di atas mengacu pada objek string.
jhodges
itulah penyalahgunaan fungsi ekstensi yang mengerikan. Memuat file bukanlah urusan kelas String.
Ben
itu dalam konteks ini. saya tidak akan membuat ini tersedia secara global atau menggunakannya di luar kelas tes. Saya menganggapnya lebih sebagai fungsi pemetaan di sini.
jhodges
28

Tidak tahu mengapa ini sangat sulit, tetapi cara paling sederhana yang saya temukan (tanpa harus merujuk ke kelas tertentu) adalah:

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

Dan kemudian memasukkan URL absolut, mis

val html = getResourceAsText("/www/index.html")
Russell Briggs
sumber
yang {}diperlukan? Kenapa tidak javaClass.getResource(path).readText()?
andrewgazelka
2
javaClass harus dipanggil pada sebuah objek sesuai dengan dokumen kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html Jika berfungsi tanpa maka go for ya life :)
Russell Briggs
3
Satu kelemahan dari metode di atas adalah membuat objek baru untuk setiap akses sumber daya. Akan lebih baik untuk menyimpan objek dummy di luar fungsi.
Russell Briggs
@RussellBriggs tbh Saya rasa itu tidak terlalu penting. Kinerja pembuatan objek sebenarnya tidak menjadi masalah jika Anda melakukan akses disk!
Qw3ry
13

Solusi yang sedikit berbeda:

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
sumber
Untuk beberapa alasan ini tidak berhasil untuk saya. Hanya memanggil kelas secara eksplisit yang berhasil. Hanya menambahkan untuk orang lain. Saya pikir itu ada hubungannya dengan tornadofx
nmu
Setelah membuat file input tes /src/test/resources, this.javaClass.getResource("/<test input filename>")bekerja seperti yang diharapkan. Terima kasih atas solusi di atas.
jkwuc89
apa yang harus dilakukan, jika fileContent bukan String dan saya tidak akan membuat objek dummy?
minizibi
1
garis miring sebelum jalur tampaknya wajib di sini, sedangkan di Jawa saya biasanya menghilangkannya.
cakraww
6

Kotlin + Cara musim semi:

@Autowired
private lateinit var resourceLoader: ResourceLoader

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

Menggunakan kelas Sumber Daya pustaka Google Guava :

import com.google.common.io.Resources;

val fileContent: String = Resources.getResource("/html/file.html").readText()
Lu55
sumber
bagus bahwa Guave melaporkan nama file jika sumber daya tidak ditemukan - jauh lebih baik untuk pemecahan masalah
Nishi
2

Inilah cara yang saya lebih suka melakukannya:

fun getResourceText(path: String): String {
    return File(ClassLoader.getSystemResource(path).file).readText()
}
kata aspen
sumber
0

Anda mungkin menemukan kelas File berguna:

import java.io.File

fun main(args: Array<String>) {
  val content = File("src/main/resources/input.txt").readText()
  print(content)
} 
Krzysztof Ziomek
sumber
3
Jawaban ini menyesatkan. Itu tidak memuat "resource", tetapi memuat file langsung dari sistem file, bukan dari classpath. Ini tidak akan berfungsi lagi setelah aplikasi dirakit karena Anda akan mencoba merujuk ke file yang tidak ada, alih-alih memuatnya dari file jar.
Ben
@ben Terima kasih atas komentar Anda. Pertanyaannya adalah tentang membaca file dari sumber daya di tes Spek kotlin.
Krzysztof Ziomek