Many times, we need to call system commands to do some processing. For example, ping the device in the program to see if it can connect, perform an automatic backup of the database, and restart the program. We must use the Process class to do this. In general, we output information during command execution to check for problems. But sometimes we also need to know when the executing process ends, because not only do we need to know when the process ends, but we also need to know what results are returned when the process completes. You might say, isn’t that what the API already provides? The process messages can be retrieved using process.getinputStream (), and the process final results can be retrieved from process.waitfor (). Sure, it looks doable, but there’s a catch.

Start with the Runtime to create an example of the Process object we need:

Java code favorites code

Process process = null; BufferedReader reader=null; Try {process = runtime.getruntime (). Exec ("ping 192.168.0.125"); reader=new BufferedReader(new InputStreamReader(process.getInputStream())); String line=null; while((line=reader.readLine())! =null){ System.out.println(line); } int result=process.waitFor(); System.out.println(result); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }Copy the code

In this example we simply ping an IP, use getInputStream() to output the process information, and then use process.waitfor () to get the result of the execution. There’s nothing wrong with it. 1. At this point if you replace process.getinputStream () with Process.geterrorStream (), there is only one output. 2. What if the execution content is EXP guide oracle database command? The rocess has not exited process has not stopped…. If you look it up on the Internet, many people will tell you that the output stream is blocking the process, causing a deadlock. 3. At this point you change process.geterrorStream () back to process.getinputStream () and find nothing and it doesn’t stop. Sure enough, the output stream blocked the process again. All standard IO operations (stdin, stdout, stderr) are redirected to the parent Process via three streams (getOutputStream(), getInputStream(), and getErrorStream()). So why should we try to get information using getInputStream() when we’re doing native commands rather than getErrorStream()? Bring the… Wait for the master answer… There are two methods to get the result returned by the process: exitValue() and waitFor(). It is often found that the flow is too clogged to get a value and an exception is reported. There’s also a solution on this website. That is, you want to empty getInputStream() and getErrorStream(). And the empties of both streams must be asynchronous. Java code favorites code

static void drainInBackground(final InputStream is) { new Thread(new Runnable(){ public void run(){ try{ while( is.read() >= 0 ); } catch(IOException e){ // return on IOException } } }).start(); } is there a good way not to write this empty stream method! Or if you don't understand, you can create the Process object directly with the ProcessBuilder. ProcessBuilder has provided a solution to this, but it is important to note ProcessBuilder's RedirecStream method. When redirectErrorStream is set to true it merges getInputStream() and getErrorStream() and automatically empties the stream without us having to deal with it ourselves. If it is false, getInputStream() and getErrorStream() separate streams and must handle them themselves, as follows:Copy the code

Java code favorites code

ProcessBuilder pBuilder =new ProcessBuilder("ping","192.168.0.125"); pbuilder.redirectErrorStream(true); process=pbuilder.start(); reader=new BufferedReader(new InputStreamReader(process.getInputStream())); String line=null; while((line=reader.readLine())! =null){ System.out.println(line); } int result=process.waitFor(); System.out.println(result); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }Copy the code

The getInputStream() stream now gives you process information and execution results whether you call native commands or other commands that configure environment variables. If ReDirecStream is set to false the result is the same as above.

Finally, there is the resulting process.waitfor () result. The API does not specify how many types of return values there are. From my test results: 0 successfully 1 failure 3 successfully! but a warning …. 2 is not tested

After a morning of continuous testing, looking for source code, looking up information, finally this has not seriously ignored the API defects thoroughly combed again. In order not to repeat other words, a lot of basic knowledge is not described, in order to focus on solving problems and existing problems.