Java ProcessBuilder:输入/输出流

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11573457/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:37:58  来源:igfitidea点击:

Java ProcessBuilder: Input/Output Stream

javaoutputstreamprocessbuilder

提问by sokeylife

I want to invoke an external program in java code, then the Google tell me that the Runtime or ProcessBuilder can help me to do this work. I have tried it, and there come out a problem the java program can't exit, that means both the sub process and the father process wait for forever. they are hanging or deadlock.

我想用java代码调用一个外部程序,然后google告诉我Runtime或者ProcessBuilder可以帮我做这个工作。我试过了,出现java程序无法退出的问题,就是子进程和父进程都在一直等待。他们正在挂起或陷入僵局。

Someone tell me the reason is that the sub process's cache is too small. when it try to give back data to the father process, but the father process don't read it in time, then both of them hang. So they advice me fork an thread to be in charge of read sub process's cache data. I do it as what they tell me, but there still some problem.

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

Then I close the output stream which get by the method getOutputStream(). Finally, the program success. But I don't know why it happen? Is there some relationship between the output steam and input stream?

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

回答by Luke Woodward

You have provided very few details in your question, so I can only provide a general answer.

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

All processes have three standard streams: standard input, standard output and standard error. Standard input is used for reading in data, standard output for writing out data, and standard error for writing out error messages. When you start an external program using Runtime.getRuntime().exec()or ProcessBuilder, Java will create a Processobject for the external program, and this Processobject will have methods to access these streams.

所有进程都有三个标准流:标准输入、标准输出和标准错误。标准输入用于读入数据,标准输出用于写出数据,标准错误用于写出错误信息。当您使用Runtime.getRuntime().exec()或启动外部程序时ProcessBuilder,Java 将为外部程序创建一个Process对象,该Process对象将具有访问这些流的方法。

These streams are accessed as follows:

这些流的访问方式如下:

  • process.getOutputStream(): return the standard inputof the external program. This is an OutputStreamas it is something your Java code will write to.
  • process.getInputStream(): return the standard outputof the external program. This is an InputStreamas it is something your Java code will read from.
  • process.getErrorStream(): return the standard error of the external program. This is an InputStreamas, like standard output, it is something your Java code will read from.
  • process.getOutputStream(): 返回外部程序的标准输入。这是OutputStream您的 Java 代码将写入的内容。
  • process.getInputStream(): 返回外部程序的标准输出。这是InputStream您的 Java 代码将从中读取的内容。
  • process.getErrorStream(): 返回外部程序的标准错误。这InputStream就像标准输出一样,是您的 Java 代码将从中读取的内容。

Note that the names of getInputStream()and getOutputStream()can be confusing.

需要注意的是的名称getInputStream()getOutputStream()可能会造成混淆。

All streams between your Java code and the external program are buffered. This means each stream has a small amount of memory (a buffer) where the writer can write data that is yet to be read by the reader. The writer does not have to wait for the reader to read its data immediately; it can leave its output in the buffer and continue.

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

There are two ways in which writing to buffers and reading from them can hang:

写入缓冲区和读取缓冲区的两种方式可能会挂起:

  • attempting to write data to a buffer when there is not enough space left for the data,
  • attempting to read from an empty buffer.
  • 当数据没有足够的空间时尝试将数据写入缓冲区,
  • 试图从空缓冲区读取。

In the first situation, the writer will wait until space is made in the buffer by reading data out of it. In the second, the reader will wait until data is written into the buffer.

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

You mention that closing the stream returned by getOutputStream()caused your program to complete successfully. This closes the standard inputof the external program, telling it that there will be nothing more for it to read. If your program then completes successfully, this suggests that your program was waiting for more input to come when it was hanging.

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

It is perhaps arguable that if you do run an external program, you should close its standard input if you don't need to use it, as you have done. This tells the external program that there will be no more input, and so removes the possibility of it being stuck waiting for input. However, it doesn't answer the question of why your external program is waiting for input.

或许有争议的是,如果您确实运行了一个外部程序,如果您不需要使用它,您应该关闭它的标准输入,就像您所做的那样。这告诉外部程序将不再有输入,因此消除了它在等待输入时卡住的可能性。但是,它没有回答为什么您的外部程序正在等待输入的问题。

Most of the time, when you run external programs using Runtime.getRuntime().exec()or ProcessBuilder, you don't often use the standard input. Typically, you'd pass whatever inputs you'd need to the external program on the command line and then read its output (if it generates any at all).

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

Does your external program do what you need it to and then get stuck, apparently waiting for input? Do you ever need to send it data to its standard input? If you start a process on Windows using cmd.exe?/k?..., the command interpreter will continue even after the program it started has exited. In this case, you should use /cinstead of /k.

您的外部程序是否按照您的需要执行操作,然后卡住了,显然是在等待输入?您是否需要将数据发送到其标准输入?如果您在 Windows 上使用 启动进程cmd.exe?/k?...,即使在它启动的程序退出后,命令解释器仍将继续。在这种情况下,您应该使用/c代替/k

Finally, I'd like to emphasise that there are two output streams, standard output and standard error. There can be problems if you read from the wrong stream at the wrong time. If you attempt to read from the external program's standard output while its buffer is empty, your Java code will wait for the external program to generate output. However, if your external program is writing a lot of data to its standard error, it could fill the buffer and then find itself waiting for your Java code to make space in the buffer by reading from it. The end result of this is your Java code and the external program are both waiting for each other to do something, i.e. deadlock.

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

This problem can be eliminated simply by using a ProcessBuilderand ensuring that you call its redirectErrorStream()method with a truevalue. Calling this method redirects the standard error of the external program into its standard output, so you only have one stream to read from.

这个问题可以简单地通过使用 aProcessBuilder并确保您redirectErrorStream()使用一个true值调用它的方法来消除。调用此方法会将外部程序的标准错误重定向到其标准输出中,因此您只有一个流可供读取。