Java 在进程关闭之前读取所有进程输出

Java 在进程关闭之前读取所有进程输出,java,process,multiprocessing,race-condition,Java,Process,Multiprocessing,Race Condition,我正在使用标准代码读取单独的进程控制台输出: ProcessBuilder b = new ProcessBuilder(exeArgs); b.redirectErrorStream(true); Process process = b.start(); try (BufferedReader inputReader= new BufferedReader(new InputStreamReader(process.getInputStream()))) { String output

我正在使用标准代码读取单独的进程控制台输出:

ProcessBuilder b = new ProcessBuilder(exeArgs);
b.redirectErrorStream(true);
Process process = b.start();
try (BufferedReader inputReader= new BufferedReader(new InputStreamReader(process.getInputStream()))) {
    String output;
    while ((output = inputReader.readLine()) != null) {
       // do something with output
    }
}
问题是,如果进程结束的速度比我读取输出的速度快,则部分输出将丢失

重现问题的最简单方法是在
try
表达式上放置一个断点,然后等待一秒钟,然后继续执行程序。这样做会阻止您获得任何输出。例如,inputReader.readLine()永远不会返回字符串


有没有办法缓存进程输出以确保它始终被完全读取?

在Windows上,控制台缓冲区大小似乎受到限制,您应该尽快读取它,以避免缓冲区溢出和丢失部分数据。在阅读了这里的几个答案并阅读了关于这个主题的博客文章后,我发现唯一可靠的解决方案是在一个单独的线程中尽快阅读控制台输出

以下是在Kotlin中实现任务的简单代码:

typealias GobblerCallback = ((e: String) -> Unit)

class StreamGobbler(private val stream: InputStream, private val lineReadCallback: GobblerCallback? = null) : Thread() {

    override fun run() {
        try {
            val reader = BufferedReader(InputStreamReader(stream, StandardCharsets.UTF_8))
            while (true) {
                val line = safeReadLine(reader) ?: break
                lineReadCallback?.invoke(line)
            }
        } catch (e: Exception) {
            // Handle exception if necessary
        }
    }

}

// Sample code that reads full process output
val gobbler1 = StreamGobbler(process.inputStream, callback)
gobbler1.start()
val gobbler2 = StreamGobbler(process.errorStream, callback)
gobbler2.start()

在Windows上,控制台缓冲区大小似乎是有限的,您应该尽快读取它,以避免缓冲区溢出和丢失部分数据。在阅读了这里的几个答案并阅读了关于这个主题的博客文章后,我发现唯一可靠的解决方案是在一个单独的线程中尽快阅读控制台输出

以下是在Kotlin中实现任务的简单代码:

typealias GobblerCallback = ((e: String) -> Unit)

class StreamGobbler(private val stream: InputStream, private val lineReadCallback: GobblerCallback? = null) : Thread() {

    override fun run() {
        try {
            val reader = BufferedReader(InputStreamReader(stream, StandardCharsets.UTF_8))
            while (true) {
                val line = safeReadLine(reader) ?: break
                lineReadCallback?.invoke(line)
            }
        } catch (e: Exception) {
            // Handle exception if necessary
        }
    }

}

// Sample code that reads full process output
val gobbler1 = StreamGobbler(process.inputStream, callback)
gobbler1.start()
val gobbler2 = StreamGobbler(process.errorStream, callback)
gobbler2.start()

你误解了这个问题。尝试运行“ls”进程并在断点处停止。它工作正常,可以打印目录内容。您误解了这个问题。尝试运行“ls”进程并在断点处停止。它工作良好,可以打印目录内容。