Why not read all lines from text file?

2019-08-26 06:37发布

问题:

In my Kotlin project in folder src/resources/ I has file pairs_ids.txt.

This is a property file:

key=value

The count of all lines are 1389.

Here code that read content of this file line by line.

open class AppStarter : Application<AppConfig>() {
    override fun getName() = "stats"

    override fun run(configuration: AppConfig?, environment: Environment?) {
        val logger = LoggerFactory.getLogger(this::class.java)

        val inputStream = javaClass.getResourceAsStream("/pairs_ids.txt")
        val isr = InputStreamReader(inputStream)
        val br = BufferedReader(isr)
        for (line in br.lines()) {
            logger.info("current_line = " + line)
        }
        br.close()
        isr.close()
        inputStream.close()
    }
}

fun main(args: Array<String>) {
    AppStarter().run(*args)
}

The problem is that count of current_line is every time different.

Start project - the count of current_line is 803.

Start again project - the count of current_line is 1140.

Why every time the count is different and not equal to 1389?

回答1:

Kotlin has some brilliant extension methods to easily deal with streams, reading lines and text and such.

Try this:

open class AppStarter : Application<AppConfig>() {
    override fun getName() = "stats"

    override fun run(configuration: AppConfig?, environment: Environment?) {
        val logger = LoggerFactory.getLogger(this::class.java)
        javaClass.getResourceAsStream("/pairs_ids.txt").bufferedReader().use { reader -> reader.readLines() }.forEach { line -> logger.info(line) }
    }
}

fun main(args: Array<String>) {
    AppStarter().run(*args)
}

When playing with input/output streams, use Kotlin's use extension methods, and do all of your processing inside of the use block.

This will handle all opening and closing of the streams so that there are no leaks, or forgetting to close/flush etc.



回答2:

Given an InputStream, you can use forEachLine to read each line separately:

inputStream.bufferedReader().use {
    it.forEachLine {
        println(it)
    }
}

Note: You should use use which is a convenient way to make sure the stream is closed once the reading is done (as user8159708 already suggested).



标签: kotlin