使用ProcessBuilder执行外部程序并提供输入

我正在尝试使用ProcessBuilder使用Java执行外部程序,但它期望来自用户的输入。

更具体地说,该程序是psql(Postgres SQL),当它执行时,程序会提示用户输入密码。 绕过它的唯一方法是在包含密码的用户主目录中保存文件,我试图避免这种情况,所以我想从Java执行程序并使用进程的输出流发送密码。

当程序不期望任何用户输入时,代码工作正常,但是当我从用户主页删除密码文件时,程序挂起。 我看到它正在被执行,但没有任何反应。 如果我调试它,它会达到while,然后在我终止进程之前没有任何反应。

这是代码,任何帮助将不胜感激。

@Test public void testSQLExecution() throws Exception { String path = "C:/tmp"; List commandList = new ArrayList(); commandList.add("psql"); commandList.add("-f"); commandList.add("test.sql"); commandList.add("-h"); commandList.add(HOST); commandList.add("-p"); commandList.add(PORT); commandList.add("-U"); commandList.add(DATABASE); commandList.add(SCHEMA); ProcessBuilder processBuilder = new ProcessBuilder(commandList); processBuilder.directory(new File(path)); processBuilder.redirectErrorStream(true); Process p = processBuilder.start(); String line; BufferedReader input = new BufferedReader(new InputStreamReader(p .getInputStream())); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(p .getOutputStream())); out.write("password"); out.newLine(); out.flush(); out.close(); // When this line is reached, the execution halts. while (input.ready() && (line = input.readLine()) != null) { System.out.println(line); } if (p.waitFor() != 0) { Assert.fail("The process did not run succesfully."); } input.close(); } 

非常感谢。

我相信提示符是STDERR,而不是STDOUT,所以你必须打开一个连接到那个的流并在那里阅读。 当您尝试从STDOUT读取时,您的代码会挂起,等待永远不会到达的输出。

编辑:我发现您已在ProcessBuilder中重定向错误流。

另一种可能性是BufferedReader正在等待换行完成读取,并且提示不以换行符结束。

已经很久了,但得到了完全相同的问题。 这是一个应该工作的SSCCE:

 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Toto { private static Logger logger = LoggerFactory.getLogger(Toto.class); static class Params { public String getUserName() { return "PUT USERNAME HERE"; } public String getHost() { return "PUT HOST HERE"; } public String getDbName() { return "PUT DBNAME HERE"; } public char[] getPassword() { return new char[]{'p','a','s','s','w','o','r','d'}; } public String getSqlFile() { return "PUT SQL COMMAND FILE HERE"; } } public static void main(String[] args) { Params params = new Params(); try { final String userName = params.getUserName(); final String host = params.getHost(); final String dbName = params.getDbName(); final char[] pass = params.getPassword(); if (userName == null || host == null || dbName == null || pass == null) { logger.error("Missing the following info to execute the SQL command file: {} {} {} {}" , userName == null ? "username": "" , host == null ? "host" : "" , dbName == null ? "database": "" , pass == null ? "password": ""); return; } List sb = new ArrayList(); sb.add("psql"); sb.add("-h"); sb.add(host); sb.add("-U"); sb.add(userName); sb.add("-d"); sb.add(dbName); sb.add("-f"); sb.add(params.getSqlFile()); // sb.add("-W"); // force password prompt logger.debug("Executing the following command: {}", sb.toString()); ProcessBuilder pb = new ProcessBuilder(sb); final Process p = pb.start(); final BufferedReader stdinReader = new BufferedReader(new InputStreamReader(p.getInputStream())); final BufferedReader stderrReader = new BufferedReader(new InputStreamReader(p.getErrorStream())); new Thread(new Runnable() { @Override public void run() { try { OutputStreamWriter s = new OutputStreamWriter(p.getOutputStream()); s.write(pass); s.write(System.getProperty("line.separator")); s.flush(); System.out.println("Pass written"); } catch(IOException e) { logger.error("Exception raised in the thread writting password to psql", e); } } }).start(); new Thread(new Runnable() { @Override public void run() { try { String s; while (( s=stdinReader.readLine()) != null) { logger.debug("psql [STDOUT]: {}", s); } } catch(IOException e) { logger.error("Exception raised in thread displaying stdout of psql", e); } } }).start(); new Thread(new Runnable() { @Override public void run() { try { String s; while (( s=stderrReader.readLine()) != null) { logger.error("psql [STDERR]: {}", s); } } catch(IOException e) { logger.error("Exception raised in thread displaying stderr of psql", e); } } }).start(); int returnVal = p.waitFor(); logger.debug("Process ended with return val {} ", returnVal); } catch (Exception e) { logger.error("Exception raised while executing the results on server", e); } } }