Пакет scala.sys
пакет sys
Члены пакета
пакет process
Этот пакет обрабатывает выполнение внешних процессов. Содержимое этого пакета можно разделить на три группы по их функциям:
-
Указание, что нужно запускать и как.Обработка ввода и вывода процесса.Выполнение процесса.
Для простого использования важна только первая группа. Запуск внешней команды может быть таким же простым, как "ls".!, или таким сложным, как создание конвейера команд, например, такого:
import scala.sys.process._
"ls" #| "grep .scala" #&& Seq("sh", "-c", "scalac *.scala") #|| "echo nothing found" lazyLines
Ниже описаны общие концепции и архитектура пакета, а затем подробнее рассмотрены каждая из упомянутых выше категорий.
Концепции и архитектура
Основой всего пакета являются классы Java Process и ProcessBuilder. Хотя нет необходимости использовать эти классы Java, они накладывают ограничения на возможности. Например, нельзя получить идентификатор процесса для любого выполняемого процесса.
При выполнении внешнего процесса можно указать имя команды, аргументы к ней, каталог, в котором она будет выполняться, и переменные среды, которые будут установлены. Для каждого выполняемого процесса можно подавать стандартный ввод через java.io.OutputStream, а читать стандартный вывод и стандартную ошибку через пару java.io.InputStream. Можно дождаться завершения выполнения процесса и получить его возвращаемое значение или убить выполняемый процесс. Все остальное должно строиться на этих функциях.
Этот пакет предоставляет DSL для запуска и цепочки таких процессов, имитируя возможность оболочек Unix передавать вывод одного процесса на вход другого или управлять выполнением последующих процессов на основе возвращаемого кода предыдущего.
Помимо этого DSL, этот пакет также предоставляет несколько способов управления вводом и выводом этих процессов, начиная от простых и удобных и заканчивая сложными и гибкими.
Когда процессы составлены, создается новый ProcessBuilder, который, при запуске, выполнит ProcessBuilder экземпляры, из которых он состоит, в соответствии с методом композиции. Если передавать один процесс другому, они будут выполняться одновременно, и каждому будет передан ProcessIO, который скопирует вывод одного на вход другого.
Что запускать и как
Центральным компонентом DSL для выполнения процесса является трайт scala.sys.process.ProcessBuilder. Он ProcessBuilder реализует DSL для выполнения процесса, создает scala.sys.process.Process, который будет обрабатывать выполнение и возвращать результаты такого выполнения вызывающему коду. Мы можем увидеть этот DSL в примере из введения: #|, #&& и #!! — методы на ProcessBuilder используемые для создания нового ProcessBuilder через композицию.
Создается ProcessBuilder либо через фабрики в объекте-компаньоне scala.sys.process.Process, либо через неявные преобразования, доступные в самом объекте этого пакета. Неявно каждый процесс создается либо из String, с аргументами, разделенными пробелами (невозможно экранировать пробелы), либо из scala.collection.Seq, где первый элемент представляет имя команды, а оставшиеся элементы — аргументы к ней. В последнем случае аргументы могут содержать пробелы.
Для дальнейшего контроля того, как будет выполняться процесс, например, для указания каталога, в котором он будет выполняться, см. фабрики в объекте-компаньоне scala.sys.process.Process.
После того, как нужный ProcessBuilder доступен, его можно выполнить различными способами, в зависимости от того, как вы хотите управлять его вводом/выводом и какого результата вы хотите получить:
-
Код возврата процесса (методы
!)Вывод процесса в виде String (методы !!)Непрерывный вывод процесса как LazyList[String] (методы lazyLines)Объект Process, его представляющий (методы run)Некоторые простые примеры этих методов:
import scala.sys.process._
// This uses ! to get the exit code
def fileExists(name: String) = Seq("test", "-f", name).! == 0
// This uses !! to get the whole result as a string
val dirContents = "ls".!!
// This "fire-and-forgets" the method, which can be lazily read through
// a LazyList[String]
def sourceFilesAt(baseDir: String): LazyList[String] = {
val cmd = Seq("find", baseDir, "-name", "*.scala", "-type", "f")
cmd.lazyLines
}
В следующем разделе мы рассмотрим более подробную информацию об управлении вводом/выводом процесса.
Обработка ввода и вывода
В базовой модели Java, после запуска Process, можно получить java.io.InputStream и java.io.OutputStream, представляющие соответственно его вывод и вход. То есть, то, что вы записываете в OutputStream, становится вводом для процесса, а вывод процесса можно прочитать из InputStream — из которых два, один представляет нормальный вывод, а другой — вывод ошибки.
Эта модель создает трудность, которая заключается в том, что код, ответственный за фактическое выполнение внешних процессов, должен принимать решения о том, как обращаться с его вводом/выводом.
Этот пакет представляет альтернативную модель: ввод/вывод выполняемого процесса контролируется объектом scala.sys.process.ProcessIO, который можно передать _в_ код, выполняющий внешний процесс. ProcessIO будет иметь прямой доступ к потокам java, связанным с вводом/выводом процесса. Однако он должен после этого закрыть эти потоки.
Тем не менее, доступны более простые абстракции. Компоненты этого пакета, обрабатывающие ввод/вывод:
-
scala.sys.process.ProcessIO: предоставляет низкоуровневую абстракцию.
scala.sys.process.ProcessLogger: предоставляет абстракцию более высокого уровня для вывода и может быть создана через её объект-компаньон.
scala.sys.process.BasicIO: библиотека вспомогательных методов для создания
ProcessIO.Сам объект этого пакета с несколькими неявными преобразованиями.Некоторые примеры обработки ввода/вывода:
import scala.sys.process._
// An overly complex way of computing size of a compressed file
def gzFileSize(name: String) = {
val cat = Seq("zcat", name)
var count = 0
def byteCounter(input: java.io.InputStream) = {
while(input.read() != -1) count += 1
input.close()
}
val p = cat run new ProcessIO(_.close(), byteCounter, _.close())
p.exitValue()
count
}
// This "fire-and-forgets" the method, which can be lazily read through
// a LazyList[String], and accumulates all errors on a StringBuffer
def sourceFilesAt(baseDir: String): (LazyList[String], StringBuffer) = {
val buffer = new StringBuffer()
val cmd = Seq("find", baseDir, "-name", "*.scala", "-type", "f")
val lazyLines = cmd lazyLines_! ProcessLogger(buffer append _)
(lazyLines, buffer)
}
Экземпляры классов java java.io.File и java.net.URL могут использоваться непосредственно как вход для других процессов, а java.io.File может использоваться в качестве вывода также. Можно даже передать один в другой напрямую без промежуточного процесса, хотя это не является целью дизайна или рекомендуемым способом использования. Например, следующий код скопирует веб-страницу в файл:
import java.io.File
import java.net.URL
import scala.sys.process._
new URL("http://www.scala-lang.org/") #> new File("scala-lang.html") !
Дополнительную информацию о других способах управления вводом/выводом можно найти в Scaladoc для связанных объектов, трайтов и классов.
Выполнение процесса
Парадоксально, это самый простой компонент из всех и тот, с которым меньше всего взаимодействуют. Он состоит только из scala.sys.process.Process и предоставляет только два метода:
exitValue(): блокирует выполнение, пока процесс не завершится, а затем возвращает код завершения. Именно это происходит, когда используется метод ! объекта ProcessBuilder.
destroy(): это приведет к завершению внешнего процесса и закрытию связанных с ним потоков.Типовые члены
Трайт BooleanProp extends Prop[Boolean]
Трайт Prop[+T] extends AnyRef
Легковесный интерфейс, оборачивающий свойство, содержащееся в некотором неопределенном отображении. Как правило, это системные свойства, но это не обязательно.
Смотрите scala.sys.SystemProperties для примера использования.
- Since
2.9
Класс ShutdownHookThread extends Thread
Минимальная обёртка Thread для улучшения хуков завершения. Она знает, как себя отменить.
- Since
2.9
Класс SystemProperties extends AbstractMap[String, String]
Двунаправленное отображение, оборачивающее системные свойства Java. Изменения в системных свойствах будут немедленно видны в отображении, а изменения, внесенные в отображение, будут немедленно применены к системным свойствам. Если установлен менеджер безопасности, который запрещает чтение или запись свойств, исключение AccessControlException будет перехвачено и проигнорировано.
Члены-значения
def addShutdownHook(body: => Unit): ShutdownHookThread
Зарегистрировать обработчик завершения работы, который будет выполнен при выходе из виртуальной машины. Обработчик регистрируется автоматически: возвращаемое значение можно игнорировать, но оно доступно в случае, если требуется дальнейшая модификация потока. Его также можно удалить, вызвав ShutdownHookThread#remove().
Обратите внимание, что обработчики завершения работы НЕ гарантируются для выполнения.
- body
код, который будет выполнен при завершении работы
- returns
поток, который выполнит обработчик завершения работы.
- См. также
def allThreads(): IndexedSeq[Thread]
Возвращает все активные потоки в группе потоков текущего потока и подгруппах.
- returns
IndexedSeq, содержащий потоки.
def env: Map[String, String]
Неизменяемая карта, представляющая текущую системную среду.
- returns
карта, содержащая переменные системной среды.
def error(message: String): Nothing
Выбрасывает RuntimeException с заданным сообщением.
- returns
Nothing.
def exit(status: Int): Nothing
Завершить JVM с заданным кодом состояния.
- returns
Nothing.
def exit(): Nothing
Завершить JVM с кодом состояния по умолчанию.
- returns
Nothing.
def props: SystemProperties
Взаимодействующая, изменяемая карта, представляющая текущие системные свойства.
- returns
SystemProperties.
- См. также
def runtime: Runtime
Удобный метод для получения текущей Runtime-инстанции.
- returns
результат
java.lang.Runtime.getRuntime()
object BooleanProp
object Prop
object ShutdownHookThread
object SystemProperties
Значения в SystemProperties могут быть использованы для доступа и управления определёнными системными свойствами. См. scala.sys.Prop для получения подробностей.
if (!headless.isSet) headless.enable()
© 2002-2019 EPFL, with contributions from Lightbend.
Licensed under the Apache License, Version 2.0.
https://www.scala-lang.org/api/2.13.0/scala/sys/index.html
Объект пакета
scala.sysсодержит методы для чтения и изменения основных аспектов виртуальной машины, а также внешнего мира.2.9