2010-07-13 33 views
2

我想用Java使用ProcessBuilder执行一个外部程序,但它需要来自用户的输入。使用ProcessBuilder执行外部程序并提供输入

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

当程序不期望任何用户输入时,代码工作正常,但是当我从用户主目录中删除密码文件时,程序挂起。我看到它正在执行,但没有任何反应。如果我调试它,它会到达一段时间,然后什么都不会发生,直到我杀死进程。

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

@Test 
public void testSQLExecution() throws Exception { 
String path = "C:/tmp"; 
List<String> commandList = new ArrayList<String>(); 
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(); 
} 

非常感谢。

+0

看到这里http://stackoverflow.com/questions/2969766/process-requires-redirected-input – Mike 2012-03-05 03:06:40

回答

0

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

编辑:我看到你重定向了ProcessBuilder中的错误流。

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

+0

这是正确的,错误输出重定向,所以它不是它。 其他可能性可能是对的,你知道如何解决这个问题,或者至少如何去确定这是怎么回事? – 2010-07-13 20:31:43

+0

读取未缓冲并将您读取的内容转储到本地stdout以查看发生了什么。然后更改代码,以便在看到提示后立即发送密码,而不必等待换行符。 – 2010-07-13 20:34:24

+0

这似乎也没有工作。 – 2010-07-13 21:13:28

0

过了很久,却遇到了完全相同的问题。下面是应该工作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<String> sb = new ArrayList<String>(); 
      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); 
     } 

    } 

} 
相关问题