当前位置: 首页 > 知识库问答 >
问题:

Java ProcessBuilder:输入/输出流

柴禄
2023-03-14

我想用java代码调用一个外部程序,然后Google告诉我Runtime或ProcessBuilder可以帮助我完成这项工作。我试过了,结果发现java程序无法退出,这意味着子进程和父进程都将永远等待。它们要么挂起,要么陷入僵局。

有人告诉我原因是子进程的缓存太小了。当它试图将数据返回给父进程时,但是父进程没有及时读取它,然后他们两个都挂起了。所以他们建议我叉一个线程来负责读取子进程的缓存数据。我按照他们告诉我的去做,但是仍然有一些问题。

然后我关闭通过getOutputStream()方法得到的输出流。最后,程序成功了。但是我不知道为什么会这样?输出蒸汽和输入蒸汽之间是否存在某种关系?

共有1个答案

吕华彩
2023-03-14

你在问题中提供的细节很少,所以我只能提供一个一般性的答案。

所有流程都有三个标准流:标准输入、标准输出和标准误差。标准输入用于读取数据,标准输出用于写入数据,标准错误用于写入错误消息。使用<code>Runtime.getRuntime()启动外部程序时。exec()或ProcessBuilder,Java将为外部程序创建一个Processobject,并且这个 object将具有访问这些流的方法。

按如下方式访问这些流:

  • process.get输出流():返回外部程序的标准输入。这是一个输出流,因为这是您的Java代码将写入的内容。
  • process.get输入流():返回外部程序的标准输出。这是一个输入流,因为你的Java代码将从中读取。
  • process.getError Stream():返回外部程序的标准错误。这是一个InpuStream,就像标准输出一样,它是您的Java代码将读取的内容。

请注意,getInpuStream()getOutpuStream()的名称可能会令人困惑。

Java代码和外部程序之间的所有流都被缓冲。这意味着每个流都有少量的内存(缓冲区),写入方可以在其中写入尚未被读取方读取的数据。编写器不必等待读取器立即读取其数据;它可以将其输出留在缓冲区中并继续。

写入缓冲区和从缓冲区读取可以通过两种方式挂起:

  • 当没有足够的数据空间时尝试将数据写入缓冲区,
  • 尝试从空缓冲区读取。

在第一种情况下,写入方将通过从缓冲区中读取数据来等待,直到缓冲区中腾出空间。在第二种情况下,读取器将等待数据写入缓冲区。

您提到关闭 getOutputStream() 返回的流会导致程序成功完成。这将关闭外部程序的标准输入,告诉它不会再读取任何内容。如果程序随后成功完成,则表明程序在挂起时正在等待更多输入。

如果你确实运行了一个外部程序,如果你不需要使用它,你应该关闭它的标准输入,这也许是有争议的。这告诉外部程序将不再有输入,因此消除了它被卡住等待输入的可能性。然而,它并没有回答为什么外部程序等待输入的问题。

大多数时候,当您使用Runtime.getRuntime(). exec()ProcessBuilder运行外部程序时,您通常不会使用标准输入。通常,您会通过命令行将所需的任何输入传递给外部程序,然后读取其输出(如果它生成任何输出)。

你的外部程序做了你需要的事情,然后被卡住了,显然是在等待输入吗?您是否需要将其数据发送到其标准输入?如果使用cmd.exe在Windows上启动进程

最后,我想强调的是有两个输出流,标准输出和标准错误。如果您在错误的时间从错误的流中读取,可能会出现问题。如果您试图在缓冲区为空时从外部程序的标准输出中读取,您的Java代码将等待外部程序生成输出。然而,如果您的外部程序正在向其标准错误写入大量数据,它可能会填满缓冲区,然后发现自己正在等待您的Java代码通过读取缓冲区来在缓冲区中腾出空间。最终结果是您的Java代码和外部程序都在等待对方做某事,即死锁。

只需使用 ProcessBuilder 并确保使用值调用其 redirectErrorStream() 方法即可消除此问题。调用此方法会将外部程序的标准错误重定向到其标准输出中,因此您只有一个流可以从中读取。

 类似资料:
  • 我想在JAVA程序中执行一个EXE文件。 它工作正常,但我希望EXE的输出立即在我的JAVA程序的文本区域中。 目前,我在“ping”命令完全完成后得到输出(因此JAVA程序挂起了大约3秒)。但是我想马上有结果... 我做错了什么? 突击队向后。 好吧,我想使用这个程序:https://iperf.fr/iperf-download.php 输出如下所示: 不过,我只有在iperf运行后才能得到这

  • 文件 std::fs::File 本身实现了 Read 和 Write trait,所以文件的输入输出非常简单,只要得到一个 File 类型实例就可以调用读写接口进行文件输入与输出操作了。而要得到 File 就得让操作系统打开(open)或新建(create)一个文件。还是拿例子来说明 use std::io; use std::io::prelude::*; use std::fs::File;

  • 回顾一下我们写的第一个 Rust 程序就是带副作用的,其副作用就是向标准输出(stdout),通常是终端或屏幕,输出了 Hello, World! 让屏幕上这几个字符的地方点亮起来。println! 宏是最常见的输出,用宏来做输出的还有 print!,两者都是向标准输出(stdout)输出,两者的区别也一眼就能看出。至于格式化输出,基础运算符和字符串格式化小节有详细说明,这里就不再啰嗦了。 更通用

  • Boost.Assign Assign帮助你把一系列的值赋给容器。它通过对operator, (逗号操作符) and operator()() (函数调用操作符)的重载,带给用户一种数据赋值的很容易的方法。除了对原型风格的代码特别有用,这个库的功能在其它时候也很有用,使用这个库有助于提高代码的可读性。使用本库中的list_of还可以就地生成无名数组。 Assign 的作者是 Thorsten Ot

  • 简介 通过前面章节的学习,你已经可以在Scheme的交互式前端中编写并执行程序了。在本章中,我讲介绍如何输入和输出。使用这个特性,你可以从文件中读取数据或向文件中写入数据。 从文件输入 open-input-file,read-char和eof-object? 函数(open-input-file filename)可以用于打开一个文件。此函数返回一个用于输入的端口。函数(read-char po

  • 本小节将会介绍基本输入输出的 Java 标准类,通过本小节的学习,你将了解到什么是输入和输入,什么是流;输入输出流的应用场景,File类的使用,什么是文件,Java 提供的输入输出流相关 API 等内容。 1. 什么是输入和输出(I / O) 1.1 基本概念 输入/输出这个概念,对于计算机相关专业的同学并不陌生,在计算中,输入/输出(Input / Output,缩写为 I / O)是信息处理系

  • 每个进程操作系统都会分配三个文件资源,分别是标准输入(STDIN)、标准输出(STDOUT)和错误输出(STDERR)。通过这些输入流,我们能够轻易得从键盘获得数据,然后在显示器输出数据。 标准输入 来自管道(Pipe)的数据也是标准输入的一种,我们写了以下的实例来输出标注输入的数据。 package main import ( "fmt" "io/ioutil" "os" ) f

  • 输入/输出 Clojure提供了很少的方法来进行输入/输出的操作。因为我们在Clojure代码里面可以很轻松的使用java里面的I/O操作方法。但是?clojure.java.io 库使得使用java的I/O方法更加简单。 这些预定义的special symbols *in* , *out* 以及 *err* 默认被设定成 stdin, stdout 以及 stderr 。如果要flush *ou