当我编写以下代码时(在ammonite中,但我认为这不重要)
("tail -f toTail.txt" lineStream) foreach(println(_))
,该程序给了我最后一行,但随后挂起,即使我在文件中写了更多,也没有出来。
API支持过程如何无界输出?
我尝试写val myStream = ("tail -f toTail.txt" lineStream_!)
但是它仍然不会返回书写
这是Scala Doc所说的:
linestream:立即返回像运行一样返回,并且通过流[String]提供了要生成的输出。获取该流的下一个元素可能会阻塞直到可用为止。
因此,我不明白为什么它会阻止
顺便说一句,我的行为与ammonite api
完全相同如果再次类型%%("tail", "-f", "toTail.txt")
,该方法只会悬挂而不会立即返回。
ProcessBuilder没有问题(至少不是您的用例造成的)。从ProcessBuilder文档中:
开始过程
要执行与ProcessBuilder关联的所有外部命令,可以使用四组方法之一。这些方法中的每一种都有各种过载和变化,以进一步控制I/O。这些方法是:
- 运行:最通用的方法,它立即返回scala.sys.process.process,外部命令同时执行。
- !:阻止所有外部命令退出,并返回执行链中最后一个的退出代码。
- !!:阻止所有外部命令退出,并返回带有产生的输出的字符串。
- lineStream:立即返回像运行一样返回,并且通过流[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
尝试一下。您需要对过程的更多控制。同样,正如文档所述:
如果一个人希望完全控制输入和输出,则可以与Run一起使用Scala.sys.process.processio。
因此:
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
它仍然立即返回,现在它挂在那里等待更多输入。如果我从tmp
目录进行echo 'fff' >> sample.txt
,则程序输出:
Another computation!
Finished
您现在有能力执行您想要的任何计算,并在发出tail -f
命令和终止它的功能后,取决于您传递给takeWhile
方法的条件(或其他关闭输入流的方法)。
有关ProcessIO
的更多详细信息,请在此处检查文档。
我认为,这与您将数据添加到文件中,而不是与ProcessBuilder
有关。例如,如果您在编辑器中使用它来添加数据,则每次保存时,它都会以不同的inode重写整个文件,而tail
则无法检测到。
尝试做tail -F
而不是tail -f
,应该有效。