当前位置: 首页 > 面试题库 >

Java exec方法,如何正确处理流

缑嘉玉
2023-03-14
问题内容

用Java产生和使用外部进程的流(IO)的正确方法是什么?据我所知,由于可能的缓冲区大小有限,因此应在与生成进程输入并行的线程中使用java结束输入流(进程输出)。

但是我不确定我是否最终需要与这些使用者线程进行同步,或者仅等待进程退出以使用waitFor方法就足够了,以确保所有进程输出实际上都被消耗了?IE是否有可能,即使进程退出(关闭其输出流),流的Java端仍存在未读数据?waitFor实际如何知道该过程何时完成?对于有问题的进程,
EOF (关闭其输入流的java末尾)表示退出。

我当前处理流的解决方案如下

public class Application {

    private static final StringBuffer output = new StringBuffer();
    private static final StringBuffer errOutput = new StringBuffer();
    private static final CountDownLatch latch = new CountDownLatch(2);

    public static void main(String[] args) throws IOException, InterruptedException {

        Process exec = Runtime.getRuntime().exec("/bin/cat");

        OutputStream procIn = exec.getOutputStream();
        InputStream procOut = exec.getInputStream();
        InputStream procErrOut = exec.getErrorStream();

        new Thread(new StreamConsumer(procOut, output)).start();
        new Thread(new StreamConsumer(procErrOut, errOutput)).start();

        PrintWriter printWriter = new PrintWriter(procIn);

        printWriter.print("hello world");
        printWriter.flush();
        printWriter.close();

        int ret = exec.waitFor();
        latch.await();

        System.out.println(output.toString());
        System.out.println(errOutput.toString());
    }

    public static class StreamConsumer implements Runnable {

        private InputStream input;
        private StringBuffer output;

        public StreamConsumer(InputStream input, StringBuffer output) {
            this.input = input;
            this.output = output;
        }

        @Override
        public void run() {
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            String line;
            try {
                while ((line = reader.readLine()) != null) {
                    output.append(line + System.lineSeparator());
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                try {
                    reader.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    latch.countDown();
                }
            }
        }

    }
}

是否有必要在此处使用锁存器,或waitFor暗示所有输出已被使用?另外,如果输出没有结束/包含新行,会readLine丢失输出还是仍然读取所有剩余内容?读取null是否意味着进程已关闭它的流的末尾-
是否还有其他可能读取null的情况?

处理流的正确方法是什么,是否可以做得比示例更好?


问题答案:

waitFor表示进程已结束,但是您不能确定从stdout和stderr收集字符串的线程也完成了,因此使用闩锁是朝着正确方向迈出的一步,但不是最佳选择。您不必等待闩锁,而可以直接等待线程:

Thread stdoutThread = new Thread(new StreamConsumer(procOut, output)).start();
Thread stderrThread = ...
...
int ret = exec.waitFor();
stdoutThread.join();
stderrThread.join();

顺便说一句,将行存储StringBuffers中是无用的工作。请ArrayList<String>改用,不做任何转换就将行放置在那里,最后以循环的方式检索它们。



 类似资料:
  • 问题内容: 任何人都可以澄清一下下面的过程是否是正确的处理流程流的方法,而没有任何流缓冲区已满和阻塞问题 我正在从Java程序中调用外部程序,正在使用ProcessBuilder来构建流程,执行之后 我正在使用一种方法来处理流程 在我的方法中,我试图处理流程流 readStream方法用于读取我的流文本。 问题答案: 不,那不是正确的方法。 首先,在某些系统上,您的代码将永远停留在调用中,因为该过

  • 问题内容: Java的I / O类,,,和他们的不同子类中都有一个可抛出的方法。 对于处理此类异常的正确方法是否存在共识? 我经常看到建议,只是默默地忽略它们,但这是错误的,至少在打开用于写的资源的情况下,关闭文件时出现问题可能意味着无法写入/发送未刷新的数据。 另一方面,在阅读资源时,我还不清楚为什么会抛出异常以及如何处理。 那么有什么标准建议吗? 问题答案: 记录下来。 您实际上不能 做任何事

  • 在我的REST API中,我有一个过滤器,该过滤器检查每个请求,以查看令牌是否是原样。下面是代码。 当用户登录到应用程序时,将调用上述代码。但是,令牌将在60分钟内过期。我知道,在令牌过期后,要么我必须带用户返回登录屏幕,要么刷新令牌。我把这里和这里的建议都看了一遍 但我不明白以下几点。 如何分配并将此令牌发送回用户?当前,当用户登录时,他将获得令牌并将其保存在一个变量中。为了使刷新的令牌工作,我

  • 问题内容: 让我们开始考虑两种类型的相机旋转: 摄像机绕点旋转(轨道): 相机旋转目标(FPS) 然后是一个更新函数,其中从眼睛/目标/上摄像机矢量中计算出投影/视图矩阵: 当摄像机的视图方向与上轴平行(在此处为z-up)时,出现这些旋转功能的问题…在那时,摄像机的行为确实令人讨厌,因此我将遇到以下故障: 所以我的问题是,我该如何调整以上代码,使相机完整旋转,而最终结果在某些边缘点上看起来并不奇怪

  • 问题内容: 昨天我对一个问题的回答之一是建议我确保我的数据库可以正确处理UTF-8字符。我该如何使用MySQL? 问题答案: 更新: 简短答案-您几乎应该始终使用字符集和排序规则。 更改数据库: 看到: 亚伦对此答案的评论如何使MySQL正确处理UTF-8 utf8_general_ci和utf8_unicode_ci有什么区别 转换指南:https : //dev.mysql.com/doc/r

  • 在 node.js中,通常的做法是将错误消息作为回调函数的第一个参数返回。在纯JS中有许多解决方案(promise,步骤,seq等),但它们似乎都无法与ICS集成。在不损失太多可读性的情况下处理错误的正确解决方案是什么? 例如: