Java
Kotlin

JavaのProcessBuilderの実行結果が欠損する問題の対策

More than 1 year has passed since last update.

下記のようなKotlinのサンプルコードを使えば、コマンドの実行結果をある程度の結果を受け取れる事ができるが、厳密にすべての出力を得ることができなかった。

これはプロセスの処理が完了していない状態でreader.readLine()の部分でnullが返ることで、処理が完了していないのにストリームの読み込みを終了してしまうことが原因だった。

class Example1(processBuilder: ProcessBuilder) {

    var input = StringBuilder()

    init {
        val process = processBuilder.start()
        this.loadInputStream(process)
        process.waitFor()
    }

    private fun loadInputStream(it: Process) {
        val reader = BufferedReader(InputStreamReader(it.inputStream))
        Thread {
            reader.use { reader ->
                while (reader.readLine() != null) {
                    input.append(reader.readLine() + "\n")
                }
            }
        }.start()
    }
}

下記のように処理の終了を待ってから明示的にループを停止することで取りこぼしがなくなりました。

class Example2(processBuilder: ProcessBuilder) {

    var running = true
    var input = StringBuilder()

    init {
        val process = processBuilder.start()
        this.loadInputStream(process)
        process.waitFor()
        this.running = false
    }

    private fun loadInputStream(it: Process) {
        val reader = BufferedReader(InputStreamReader(it.inputStream))
        Thread {
            reader.use { reader ->
                while (running) {
                    input.append(reader.readLine() + "\n")
                }
            }
        }.start()
    }
}

この現象は一瞬で処理結果が返ってくるものから、長い時間かけて緩やかに結果を返すジョブに対しても同じように発生しました。