【发布时间】:2018-08-06 15:58:50
【问题描述】:
我正在使用 ProcessBuilder 启动一个进程,如下所示:
val pb = ProcessBuilder("/path/to/process")
pb.redirectErrorStream(true)
val proc = pb.start()
我想用进程的标准输出做两件事:
- 持续监控其最近的输出线
- 将所有行记录到文件中
据我所知,为了完成这两件事,我需要“拆分”从proc.inputStream 获得的 InputStream,以便每一行都镜像到另外两个 InputStream:一个可以使用记录到一个文件,另一个用于解析和监视进程的状态。
一种选择是让一个从 InputStream 读取的线程触发一个事件,每行读取到“订阅者”,我认为这应该可以正常工作,但我希望提出一个更通用的“Tee”类型功能将公开 InputStreams 以供任何人使用。基本上是这样的:
val pb = ProcessBuilder("/path/to/process")
pb.redirectErrorStream(true)
val proc = pb.start()
val originalInputStream = proc.inputStream
val tee = Tee(originalInputStream)
// Every line read from originalInputStream would be
// mirrored to all branches (not necessarily every line
// from the beginning of the originalInputStream, but
// since the start of the lifetime of the created branch)
val branchOne: InputStream = tee.addBranch()
val branchTwo: InputStream = tee.addBranch()
我对@987654324@ 类进行了拍摄,但我不确定在addBranch 方法中要做什么:
class Tee(inputStream: InputStream) {
val reader = BufferedReader(InputStreamReader(inputStream))
val branches = mutableListOf<OutputStream>()
fun readLine() {
val line = reader.readLine()
branches.forEach {
it.write(line.toByteArray())
}
}
fun addBranch(): InputStream {
// What to do here? Need to create an OutputStream
// which readLine can write to, but return an InputStream
// which will be updated with each future write to that
// OutputStream
}
}
编辑:我最终得到的Tee 的实现如下:
/**
* Reads from the given [InputStream] and mirrors the read
* data to all of the created 'branches' off of it.
* All branches will 'receive' all data from the original
* [InputStream] starting at the the point of
* the branch's creation.
* NOTE: This class will not read from the given [InputStream]
* automatically, its [read] must be invoked
* to read the data from the original stream and write it to
* the branches
*/
class Tee(inputStream: InputStream) {
val reader = BufferedReader(InputStreamReader(inputStream))
var branches = CopyOnWriteArrayList<OutputStream>()
fun read() {
val c = reader.read()
branches.forEach {
// Recreate the carriage return so that readLine on the
// branched InputStreams works
it.write(c)
}
}
fun addBranch(): InputStream {
val outputStream = PipedOutputStream()
branches.add(outputStream)
return PipedInputStream(outputStream)
}
}
【问题讨论】: