The method of calling external programs in Java "Magic Hall"

This article mainly introduces the Java Magic Hall: The related knowledge of calling external programs. This article introduces you in very detailed, and has a certain reference value for everyone's study or work. Please refer to it for friends who need it.

Preface

Although Java has all the internal organs, there are always weaknesses, such as obtaining hardware information such as CPU. Of course, we can call C/C++ through JNI to obtain it. However, for coders who are not familiar with C/C++ and Windows API, it is a series of complicated learning and stepping. Pit process. Can it be done in a simpler and lower cost of learning? The answer is yes, in the case of function realization in the first place, borrowing the stone from another mountain is the most concise and powerful way.

Knowing java.lang.Runtime#execmethod

Function: Used to call external programs and redirect the standard input, standard output and standard error of the external program to the buffer pool. The function is the same as the "run" of windows.

image

Overload method description

Runtime#exec(String command);
Runtime#exec(String command, String[] envp);
Runtime#exec(String command, String[] envp, File workdir);
Runtime#exec(String[] cmdArray);
Runtime#exec(String[] cmdArray, String[] envp);
Runtime#exec(String[] cmdArray, String[] envp, File workdir);

String[] envp is used as the session-level environment variable set before calling the command.
1.1. Variable scope: After the command runs, the environment variable set by this parameter will be invalid;
1.2. Setting method: variableName=variableValue, such as Process proc = r.exec("cmd /c dir> %dest%", new String[]{"dest=c:\dir.txt"});File workdir is used to set the current working directory. For example, if we need to execute the echo.exe program located in D:\tools, then we can call Process proc = r like this .exec("echo.exec", null, new File("D:\tools")); String command is the external program that needs to be called, as well as command line parameters, etc. System commands are called under Windows. Commands such as dir are interpreted and executed by the cmd parser. Therefore, if you write "dir" directly, it will be considered that there is a "dir.exe" file in the current working directory, and of course the execution will fail; Calling ls etc. under Linux is the same reason, so please call cmd and shell commands as follows:
3.1. The way to call CMD command is Process proc = r.exec(String.format("cmd /c %s", "cmd Commands, such as dir, type, etc.")), if you want to start a new console to execute commands, you only need to rewrite dir to start dir;
3.2. The way to call the Shell command is Process proc = r.exec(String.format("/bin/sh -c %s", "shell command, such as ls, cat, etc.")), if you want to start a new Terminal To execute the command, you only need to rewrite ls to xterm -e ls; String[] cmdArray has the same function as String command, but each part of the command line will be separated independently as an element in the array. For example, cmd /c dir must be divided into new String[]{"cmd", "/c", "dir"}, but cannot be divided into new String[]{"cmd /c", "dir"}.

##Input redirection
Stop talking nonsense, just look at the code!

try {
    
                                                          
 String cmd = "cmd /c start cmd.exe";                                    
 Process child = Runtime.getRuntime().exec(cmd);                               
 OutputStream output = child.getOutputStream();                               
 output.write("cd C:/ /r/n".getBytes());                                   
 output.flush();                                               
 output.write("dir /r/n".getBytes());                                    
 output.close();                                               
}                                                        
catch (IOException e) {
    
    }  

##Output redirection
Note: Direct use of> or >> to perform standard output redirection is not supported.

String cmd = "/path/to/getipconfig.bat"; // 自己写的bat脚本文件,里面包含ipconfig /all命令。
Process p;                                                   
                                                           
try {
    
                                                          
 p = Runtime.getRunTime().exec(cmd);                                     
 InputStream input = p.getInputStream();                                   
 InputStreamReader streamReader = new InputStreamReader(input);                       
 BufferedReader bufReader = new BufferedReader(streamReader);                        
 String line = null;                                             
                                                           
 while ((line = bufReader.readLine()) != null) {
    
                                   
  System.out.println(line);                                          
 }                                                      
}                                                        
catch (IOException e) {
    
    }     

Why can't I use >and >>implement output redirection?

The input stream and error information stream passed Process实例.getInputStream()and Process实例.getErrorStream()obtained are provided by the current Java program in the buffer pool, instead of directly obtaining the standard output stream and standard error stream of the external program.
That Runtime#execis, when the external program is called, the standard output stream and the standard error stream of the external program have been taken over by the Java program. Then the attempt to pass >and >>implement output redirection in the command is obviously no longer effective.

image

In addition, the capacity of the buffer pool is fixed, so if the external program continuously outputs content to the buffer pool during operation, when the buffer pool is full, the external program will suspend operation until the buffer pool has a space to receive the output content of the external program. . (This problem occurs when using the xcopy command to copy a large number of files) The
solution is that the current Java program keeps reading the contents of the buffer pool to free up space in the buffer pool. Such as:

Runtime r = Runtime.getRuntime();
try{
    
    
 Process proc = r.exec("cmd /c dir"); // 假设该操作为造成大量内容输出
 // 采用字符流读取缓冲池内容,腾出空间
 BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream(), "gbk")));
 String line = null;
 while ((line = reader.readLine()) != null){
    
    
   System.out.println(line);
 }

 // 或采用字节流读取缓冲池内容,腾出空间
 // ByteArrayOutputStream pool = new ByteArrayOutputStream();
 // byte[] buffer = new byte[1024];
 // int count = -1;
 // while ((count = proc.getInputStream().read(buffer)) != -1){
    
    
 //  pool.write(buffer, 0, count);
 //  buffer = new byte[1024];
 // }
 // System.out.println(pool.toString("gbk"));

 int exitVal = proc.waitFor();
 System.out.println(exitVal == 0 ? "成功" : "失败");
}
catch(Exception e){
    
    
 e.printStackTrace();
}

####Note: The external program will be closed automatically after the execution is over. Otherwise, no matter it is a character stream or a byte stream, the Java process will be blocked because the data cannot be read or the end of the stream cannot be read.

Java.lang.ProcessBuilder to simplify input and output redirection

The function is the same as java.lang.runtime#exec, except that java.lang.ProcessBuilder only receives the command line and passes it to java.lang.ProcessBuilder#command() in the form of an array.

##Basic usage

ProcessBuilder pb = new ProcessBuilder();                                                                 
// pb.command("cmd /c dir"); 这样会报错                                                                  
// 或者写到new ProcessBuilder("cmd", "/c", "dir")                                                             
pb.command("cmd", "/c", "dir");                                                                      
try {
    
                                                                                       
 Process process = pb.start();                                                                     
 // 后面都是操作Process实例的方法                                                                    
}                                                                                     
catch (IOException e){
    
    }   

##Redirect

public ProcessBuilder redirectInput(File file) // 输入重定向                                                       
public ProcessBuilder redirectOutput(File file) // 输出重定向                                                       
public ProcessBuilder redirectError(File file) // 异常重定向      

####Example

try {
    
                                                                                      
 ProcessBuilder pb = new ProcessBuilder("cmd");                                                            
 // 在标准输入中,通过换行符分隔多行命令。                                                              
 // commands.txt的内容为                                                                       
 // javac Demo.java                                                                          
 // java Demo                                                                             
 File commands = new File("/path/to/commands.txt");                                                          
 File error = new File("/path/to/error");                                                               
 File output = new File("/path/to/output");                                                              
                                                                                         
 pd.redirectInput(commands);                                                                     
 pd.redirectOutput(output);                                                                      
 pd.redirectError(error);                                                                       
                                                                                         
 pd.start();                                                                             
}                                                                                    
catch(Exception e) {
    
                                                                               
 e.printStackTrace();                                                                         
}               

java.lang.ProcessAPI description

// 以非阻塞方式获取子进程执行的返回值(习惯0表示正常结束)。若子进程尚未完成时调用该方法,则会报异常`java.lang.IllegalThreadStateException`
int exitValue()      
// 以阻塞方式获取子进程执行的返回值。若进程尚未完成则会等待子进程完成后才恢复当前线程。
// 问题:若子进程无法正常关闭,则会导致Java线程一直挂起;
// 返回值为子进程的退出码
int waitFor()// 如果超时前子进程结束,那么返回`true` ,否则返回`false`
boolean waitFor(long timeout, TimeUnit unit)
// 强行终止子进程,但调用后子进程不会马上被终止,所以立即调`boolean isAlive()`方法可能会返回`true`,因此需配合`waitFor`使用。
void destory()
// 默认实现为调用`void destory()`方法。从JDK1.8开始提供。
Process destoryForcibly()
// 如果子进程还没结束则返回`true` 。从JDK1.8开始提供。                                          
boolean isAlive()
// 获取子进程的异常输出流,如果子进程以`ProcessBuilder`创建,且通过`ProcessBuilder.redirectError`设置重定向,那么该方法返回`null`                          
InputStream getErrorStream()
// 获取子进程的标准输出流,如果子进程以`ProcessBuilder`创建,且通过`ProcessBuilder.redirectOutput`设置重定向,那么该方法返回`null`
InputStream getInputStream() 
// 获取子进程的标准输入流,如果子进程以`ProcessBuilder`创建,且通过`ProcessBuilder.redirectInput`设置重定向,那么该方法返回`null`
OutputStream getOutputStream()

So far this article about Java Magic Hall: Calling External Programs is here. I hope everyone will support you more in the future.

Guess you like

Origin blog.csdn.net/p1830095583/article/details/114931737