Традиционный подход в Java для выполнения внешнего процесса состоит в том, чтобы запустить новый Process
, запустить два потока для использования его inputStream
и errorStream
, а затем вызвать его блокировку Process.waitFor()
, чтобы дождаться внешнего команда завершена.
Как это можно сделать в (почти) неблокирующем стиле с Kotlin сопрограммами?
Я пробовал таким образом. Есть ли у вас какие-либо предложения по его улучшению?
(Как асинхронно читать потоки, также вызвать ProcessBuilder.start()
в withContext(Dispatchers.IO)
, слишком много обращений к Dispatchers.IO, ...?)
suspend fun executeCommand(commandArgs: List<String>): ExecuteCommandResult {
try {
val process = ProcessBuilder(commandArgs).start()
val outputStream = GlobalScope.async(Dispatchers.IO) { readStream(process.inputStream) }
val errorStream = GlobalScope.async(Dispatchers.IO) { readStream(process.errorStream) }
val exitCode = withContext(Dispatchers.IO) {
process.waitFor()
}
return ExecuteCommandResult(exitCode, outputStream.await(), errorStream.await())
} catch (e: Exception) {
return ExecuteCommandResult(-1, "", e.localizedMessage)
}
}
private suspend fun readStream(inputStream: InputStream): String {
val readLines = mutableListOf<String>()
withContext(Dispatchers.IO) {
try {
inputStream.bufferedReader().use { reader ->
var line: String?
do {
line = reader.readLine()
if (line != null) {
readLines.add(line)
}
} while (line != null)
}
} catch (e: Exception) {
// ..
}
}
return readLines.joinToString(System.lineSeparator())
}