Làm thế nào để đọc một tệp văn bản từ các tài nguyên trong Kotlin?


94

Tôi muốn viết một bài kiểm tra Spek trong Kotlin. Thử nghiệm sẽ đọc một tệp HTML từsrc/test/resources thư mục. Làm thế nào để làm nó?

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

Câu trả lời:


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

30
Đối với tôi đây không làm việc, tôi đã phải thay đổi nó đểthis::class.java.classLoader.getResource("/html/file.html").readText()
pavlos163

4
Đối với tôi, cả hai tùy chọn này đều hoạt động trong một ứng dụng Android (lưu ý phần bổ sung /ở một trong số chúng, cái này phải được xóa trong cái còn lại): 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()hiện công việc thậm chí ngắn hơn
Frank Neblung

28

một giải pháp hơi khác:

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

Sử dụng tốt một chức năng mở rộng! Nhưng tại sao bạn sử dụng một hàm lambda ở đây? Điều đó không có nhiều ý nghĩa đối với tôi. Hơn nữa, thisphần đó không hoạt động với tôi. Vì vậy, tôi đề xuất những điều sau:fun String.asResource(): URL? = object {}.javaClass.getResource(this)
Qw3ry

Tôi thích phương pháp làm việc này khi bạn khai báo tệp, sau đó làm việc trên nội dung của tệp đó. Tôi đoán sở thích cá nhân. thistrong ví dụ trên đề cập đến đối tượng chuỗi.
jhodges

đó là sự lạm dụng khủng khiếp của chức năng mở rộng. Việc tải tệp không phải là mối quan tâm của lớp String.
Ben

nó là trong bối cảnh này. tôi sẽ không cung cấp nó trên toàn cầu hoặc sử dụng nó bên ngoài các lớp thử nghiệm. Tôi coi nó nhiều hơn một chức năng ánh xạ ở đây.
jhodges

25

Không hiểu tại sao điều này lại khó đến vậy, nhưng cách đơn giản nhất mà tôi đã tìm thấy (mà không cần phải tham chiếu đến một lớp cụ thể) là:

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

Và sau đó chuyển vào một URL tuyệt đối, ví dụ:

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

được {}yêu cầu? Tại sao không chỉ javaClass.getResource(path).readText()?
andrewgazelka

1
javaClass phải được gọi trên một đối tượng theo tài liệu kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html Nếu nó hoạt động mà không có thì hãy tiếp tục cuộc sống :)
Russell Briggs

3
Một nhược điểm của phương pháp trên là nó tạo ra một đối tượng mới cho mọi truy cập tài nguyên. Sẽ tốt hơn nếu lưu trữ đối tượng giả bên ngoài hàm.
Russell Briggs

@RussellBriggs tbh Tôi không nghĩ điều đó quan trọng lắm. Hiệu suất tạo đối tượng không thực sự là một vấn đề nếu bạn truy cập đĩa!
Qw3ry

13

Một giải pháp hơi khác:

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

            var fileContent = ""

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

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

Vì một số lý do mà điều này không hiệu quả với tôi. Chỉ gọi một cách rõ ràng lớp đã hoạt động. Chỉ thêm cho những người khác. Tôi nghĩ rằng nó có cái gì để làm với tornadofx
NMU

Sau khi tạo một tệp đầu vào thử nghiệm /src/test/resources, this.javaClass.getResource("/<test input filename>")hoạt động như mong đợi. Cảm ơn vì giải pháp trên.
jkwuc89

phải làm gì, nếu fileContent không phải là String và tôi sẽ không tạo bất kỳ đối tượng giả nào?
minizibi

1
dấu gạch chéo trước đường dẫn dường như bắt buộc ở đây, trong khi trong Java tôi thường bỏ qua nó.
cakraww

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

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

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

4

Sử dụng lớp Tài nguyên của thư viện Google Guava :

import com.google.common.io.Resources;

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

thật tuyệt khi Guave báo cáo tên tệp nếu không tìm thấy tài nguyên - tốt hơn nhiều để khắc phục sự cố
Nishi

0

Bạn có thể thấy lớp Tệp hữu ích:

import java.io.File

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

3
Câu trả lời này gây hiểu lầm. Điều đó không tải "tài nguyên" nhưng tải tệp trực tiếp từ hệ thống tệp, thay vì đường dẫn classpath. Nó sẽ không còn hoạt động sau khi ứng dụng được lắp ráp vì bạn sẽ cố gắng tham khảo các tệp không tồn tại, thay vì tải chúng từ tệp jar.
Ben

@ben Cảm ơn bình luận của bạn. Câu hỏi về việc đọc tệp từ tài nguyên trong kiểm tra kotlin Spek.
Krzysztof Ziomek

0

Đây là cách mà tôi thích làm hơn:

fun getResourceText(path: String): String {
    return File(ClassLoader.getSystemResource(path).file).readText()
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.