当我写下面的代码时(在菊石中,但我不认为这很重要)
("tail -f toTail.txt" lineStream) foreach(println(_))
,程序给我最后一行作为打算然后挂起,即使我在文件中写了更多,也没有任何结果。
API如何支持具有无限输出的过程?
我尝试写val myStream = ("tail -f toTail.txt" lineStream_!)
但它仍然没有回写
以下是scala doc所说的内容:
lineStream:像run一样立即返回,生成的输出通过Stream [String]提供。获取该流的下一个元素可能会阻塞,直到它可用为止。
因此,我不明白为什么会阻止
顺便说一下,我与Ammonite API具有完全相同的行为
如果再次键入%%("tail", "-f", "toTail.txt")
,该方法只会挂起并且不会立即返回。
答案 0 :(得分:1)
ProcessBuilder没有问题(至少没有一个源于您的用例)。来自ProcessBuilder documentation:
启动流程
要执行与ProcessBuilder关联的所有外部命令,可以使用四组方法中的一组。这些方法中的每一种都具有各种过载和变化,以实现对I / O的进一步控制。这些方法是:
- run:最通用的方法,它立即返回一个scala.sys.process.Process,并且外部命令同时执行。
- !:阻塞,直到所有外部命令退出,并返回执行链中最后一个的退出代码。
- !!:阻塞,直到所有外部命令退出,并返回一个生成输出的String。
- 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。
举个例子:
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
的详细信息,请查看documentation here。
答案 1 :(得分:1)
我认为,这与您向文件添加数据的方式有关,而与ProcessBuilder
无关。如果您在编辑器中使用它来添加数据,它会在每次保存时使用不同的inode重写整个文件,并且tail
没有检测到。
尝试执行tail -F
代替tail -f
,这应该有用。