С ProcessBuilder проблем нет (по крайней мере, тех, которые вытекают из вашего варианта использования). Из документации по ProcessBuilder:
Запуск процессов
Для выполнения всех внешних команд, связанных с ProcessBuilder, можно использовать одну из четырех групп методов. Каждый из этих методов имеет различные перегрузки и варианты для обеспечения дополнительного контроля над вводом-выводом. Эти методы:
- run: наиболее общий метод, он немедленно возвращает scala.sys.process.Process, а внешняя команда выполняется одновременно.
- !: блокируется до выхода всех внешних команд и возвращает код выхода последней в цепочке выполнения.
- !!: блокируется до выхода всех внешних команд и возвращает строку со сгенерированным выводом.
- lineStream: возвращается немедленно, как и run, а генерируемый вывод предоставляется через Stream[String]. Получение следующего элемента этого потока может быть заблокировано, пока он не станет доступным. Этот метод вызовет исключение, если код возврата отличен от нуля. Если это нежелательно, используйте функцию lineStream_! метод.
В документации четко указано, что lineStream
может блокироваться до тех пор, пока не станет доступной следующая строка. Поскольку природа tail -f
представляет собой бесконечный поток строк lineBreak
, программа заблокируется в ожидании появления следующей строки.
Для следующего предположим, что у меня есть файл: /Users/user/tmp/sample.txt
и его содержимое:
boom
bar
cat
Почему lineStream_!
не ошибается
import scala.language.postfixOps
import scala.sys.process._
object ProcessBuilder extends App {
val myStream: Stream[String] = ("tail /Users/user/tmp/sample.txt" lineStream_!)
println("I'm after tail!")
myStream.filter(_ != null).foreach(println)
println("Finished")
System.exit(0)
}
Выходы:
I'm after tail!
boom
bar
cat
Finished
Итак, вы видите, что lineStream_!
немедленно вернулся. Потому что природа команды конечна.
Как немедленно вернуться из команды, которая производит бесконечный вывод:
Давайте попробуем это с tail -f
. Вам нужно больше контроля над вашим процессом. Опять же, как говорится в документации:
Если требуется полный контроль над вводом и выводом, можно использовать scala.sys.process.ProcessIO с run.
Итак, для примера:
import java.io.{BufferedReader, InputStreamReader}
import scala.language.postfixOps
import scala.sys.process._
object ProcessBuilder extends App {
var reader: BufferedReader = _
try {
var myStream: Stream[String] = Stream.empty
val processIO = new ProcessIO(
(os: java.io.OutputStream) => ??? /* Send things to the process here */,
(in: java.io.InputStream) => {
reader = new BufferedReader(new InputStreamReader(in))
myStream = Stream.continually(reader.readLine()).takeWhile(_ != "ff")
},
(in: java.io.InputStream) => ???,
true
)
"tail -f /Users/user/tmp/sample.txt".run(processIO)
println("I'm after the tail command...")
Thread.sleep(2000)
println("Such computation performed while tail was active!")
Thread.sleep(2000)
println("Such computation performed while tail was active again!")
println(
s"Captured these lines while computing: ${myStream.print(System.lineSeparator())}")
Thread.sleep(2000)
println("Another computation!")
} finally {
Option(reader).foreach(_.close())
}
println("Finished")
System.exit(0)
}
Выходы:
I'm after the tail command...
Such computation performed while tail was active!
Such computation performed while tail was active again!
boom
bar
cat
Он по-прежнему возвращается немедленно, и теперь он просто висит там, ожидая большего ввода. Если я делаю echo 'fff' >> sample.txt
из каталога tmp
, программа выводит:
Another computation!
Finished
Теперь у вас есть возможность выполнять любые вычисления, которые вы хотите, после выдачи команды tail -f
и возможность завершить ее в зависимости от условия, которое вы передаете методу takeWhile
(или другим методам, закрывающим входной поток).
Дополнительные сведения о ProcessIO
см. в документации здесь.
person
pedromss
schedule
04.09.2017
"tail -f foo.txt".lineStream.foreach(println)
не вернется сразу же, он должен сидеть там и распечатывать новые строки по мере их добавления кfoo.txt
. Она делает первое (сидит там), но не второе — никаких дополнительных строк не печатается, так как они добавляются в файл после запуска команды. - person Dima   schedule 04.09.2017val stream = "tail -f".lineStream
— возвращает сразу.stream.foreach(println)
— выводит конец файла, а затем блоки, но не выводит больше строк по мере их добавления. - person Dima   schedule 04.09.2017