จะอ่านไฟล์ข้อความจากแหล่งข้อมูลใน Kotlin ได้อย่างไร?


97

ฉันต้องการเขียนการทดสอบ Spek ใน Kotlin การทดสอบควรอ่านไฟล์ 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") {
                ...
            }
        }
    }
})

คำตอบ:


116
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

20
val fileContent = javaClass.getResource("/html/file.html").readText()ทำงานให้สั้นลงกว่าเดิม
Frank Neblung

1
ผิดปกติพอฉันต้องการเฉือนชั้นนำเสมอ เช่นถ้าไฟล์อยู่ในไดเร็กทอรี root ของทรัพยากรคุณยังคงต้องอ้างถึงไฟล์นั้นเป็น "/file.html"
Somaiah Kumbera

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
เบ็น

มันอยู่ในบริบทนี้ ฉันจะไม่ทำให้สิ่งนี้พร้อมใช้งานทั่วโลกหรือใช้นอกชั้นเรียนทดสอบ ฉันคิดว่ามันเป็นฟังก์ชันการทำแผนที่มากกว่าที่นี่
jhodges

28

ไม่รู้ว่าทำไมเรื่องนี้ถึงยาก แต่วิธีที่ง่ายที่สุดที่ฉันพบ (โดยไม่ต้องอ้างถึงคลาสใดชั้นหนึ่ง) คือ:

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

จากนั้นส่งผ่าน URL ที่สมบูรณ์เช่น

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

ถูก{}ต้อง? ทำไมไม่เพียงjavaClass.getResource(path).readText()?
andrewgazelka

2
javaClass ต้องถูกเรียกใช้บนวัตถุตามเอกสารkotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html ถ้ามันใช้งานได้โดยไม่ต้องใช้ชีวิต :)
รัสเซลบริกส์

3
ข้อเสียอย่างหนึ่งของวิธีการข้างต้นคือสร้างวัตถุใหม่สำหรับทุกการเข้าถึงทรัพยากร ควรเก็บวัตถุจำลองไว้นอกฟังก์ชันจะดีกว่า
Russell Briggs

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

ด้วยเหตุผลบางอย่างสิ่งนี้ไม่ได้ผลสำหรับฉัน การเรียกชั้นเรียนอย่างชัดเจนเท่านั้นที่ใช้งานได้ เพียงแค่เพิ่มสำหรับคนอื่น ๆ ฉันคิดว่ามันเกี่ยวข้องกับทอร์นาโดส
nmu

หลังจากสร้างไฟล์อินพุตทดสอบ/src/test/resourcesแล้ว this.javaClass.getResource("/<test input filename>")ทำงานตามที่คาดไว้ ขอบคุณสำหรับวิธีแก้ปัญหาด้านบน
jkwuc89

จะทำอย่างไรถ้า fileContent ไม่ใช่ String และฉันจะไม่สร้างวัตถุจำลองใด ๆ
minizibi

1
เครื่องหมายทับนำหน้าเส้นทางดูเหมือนบังคับที่นี่ในขณะที่ใน Java ฉันมักจะข้ามมัน
cakraww

6

Kotlin + ทางสปริง:

@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

คุณอาจพบว่าคลาสไฟล์มีประโยชน์:

import java.io.File

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

3
คำตอบนี้ทำให้เข้าใจผิด ซึ่งไม่ได้โหลด "ทรัพยากร" แต่โหลดไฟล์โดยตรงจากระบบไฟล์แทนที่จะเป็น classpath มันจะไม่ทำงานอีกต่อไปหลังจากประกอบแอปพลิเคชันแล้วเนื่องจากคุณจะพยายามอ้างถึงไฟล์ที่ไม่มีอยู่แทนที่จะโหลดจากไฟล์ jar
เบ็น

@ben ขอบคุณสำหรับความคิดเห็นของคุณ คำถามเกี่ยวกับการอ่านไฟล์จากทรัพยากรในการทดสอบ kotlin Spek
Krzysztof Ziomek
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.