在Java中使用ProcessBuilder
时,我遇到了从进程获取输出的问题。我的应用程序是一个GUI应用程序,我允许用户将用户条目添加到包含用户凭据的文件中。密码在文件中加密。 GUI应用程序具有“添加用户”和“更改密码”按钮。当按下这些按钮中的任何一个时,执行以下功能,该功能执行外部程序以加密密码。这似乎适用于Solaris和Windows OK,但我在Linux上运行它时遇到问题(OEL 6.x,Java 1.7)。对于Linux,“添加用户”功能可以使密码加密,但“更改密码”无法正确执行外部程序。
我已经在这里阅读了其他答案,并且我在线程中消耗了输入和错误流。
根据一些调试输出,我可以看到线程和进程退出的顺序似乎决定了我如何从进程输出。
private boolean getObfuscatedPassword(String passAsPlainText, StringBuilder obfPass)
{
//Check path of binary
File cmdBin = new File(txtPath.getText());
boolean retVal = true;
if (passAsPlainText.length() == 0)
{
JOptionPane.showMessageDialog(null,
"The given password is empty",
"Error", JOptionPane.ERROR_MESSAGE);
return false;
}
if (!cmdBin.exists())
{
JOptionPane.showMessageDialog(null,
"The binary does not exist in the specified path. Choose a different binary location.",
"Error", JOptionPane.ERROR_MESSAGE);
return false;
}
//execute command with options
try{
String strCmd = new String(txtPath.getText() + " -encryptPW " + passAsPlainText );
String [] strCmds = {txtPath.getText(), "-encryptPW", passAsPlainText};
//Debug
for (int i =0; i < 3; i++)
{
System.out.println(strCmds[i]);
}
ProcessBuilder pb = new ProcessBuilder(strCmds);
//pb.inheritIO();
Process cmdProc = pb.start();
StringBuilder strBOut = new StringBuilder();
LogStreamReader lsrOut = new LogStreamReader(cmdProc.getInputStream(), strBOut);
BufferedReader bfOut = new BufferedReader(new InputStreamReader(cmdProc.getInputStream()));
Thread td1 = new Thread(lsrOut, "LogStream1");
td1.start();
td1.setPriority(Thread.MAX_PRIORITY);
StringBuilder strBErr = new StringBuilder();
LogStreamReader lsrErr = new LogStreamReader(cmdProc.getErrorStream(), strBErr);
Thread td2 = new Thread(lsrErr, "LogStream2");
td2.start();
/* This was an attempt to move the LogStreamReader to the main thread of execution, to see if it works differently than the threaded version.
try {
String line;
while ((line = bfOut.readLine()) != null)
{
System.out.println(line);
strBOut.append(line);
}
System.out.println("reached thread null main");
bfOut.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
*/
cmdProc.waitFor();
System.out.println(cmdProc.exitValue());
td1.join();
td2.join();
if (strBErr.length() > 0)
{
System.out.println(strBErr.toString());
JOptionPane.showMessageDialog(null,
"(Err1) Unable to encrypt the password. The executable version or path may be incorrect" ,
"Error", JOptionPane.ERROR_MESSAGE);
retVal = false;
}
else if (strBOut.length() == 0)
{
JOptionPane.showMessageDialog(null,
"(Err2) Unable to encrypt the password. The executable version or path may be incorrect" ,
"Error", JOptionPane.ERROR_MESSAGE);
retVal = false;
}
else
{
obfPass.append(strBOut.toString());
}
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(null, ex.toString(), "Error", JOptionPane.ERROR_MESSAGE);
retVal = false;
}
return retVal;
}
并且LogStreamReader
基于我在其他Java帖子中看到的StreamGobbler
:
public class LogStreamReader implements Runnable {
private BufferedReader reader;
private StringBuilder strBldr;
private InputStreamReader isr;
public LogStreamReader(InputStream is, StringBuilder strb){
this.isr = new InputStreamReader(is);
this.reader = new BufferedReader(isr);
this.strBldr = strb;
}
public void run() {
// TODO Auto-generated method stub
try {
String line;
while ((line = reader.readLine()) != null)
{
System.out.println(line);
strBldr.append(line);
}
System.out.println("reached thread null");
reader.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
}
结果
/home/XXXXX/x86_64_Linux_6X.64/gnu444-g-tp/bin/tool
-encryptPW
ss
F4aru5cF95Lde5k507i3D7VRK7aru5cF95Lde5k507i3mVIZkJeD5DeMV2nBOPU1BxUon8NZkJeD5DeMV2nBOPU1BNk
reached thread null
reached thread null main
0
-------------------------end of add user
/home/XXXXXXX/x86_64_Linux_6X.64/gnu444-g-tp/bin/tool
-encryptPW
ss
DqOZEtQ93tnHotIB-rGvxrhjUrOZEtQ93tnHotIB-rGvxqnzGjU3t3UmfCNXcdeFX9eKNwnzGjU3t3UmfCNXcdeFXTk
reached thread null
reached thread null main
0
-----------------------end of add user
-------------------start "change password" button
/home/XXXXX/x86_64_Linux_6X.64/gnu444-g-tp/bin/tool
-encryptPW
dddd
reached thread null main <-- thread or main is exiting before process
0
reached thread null
-------------------end of "change Password"
-------------------start of "change password again"
/home/XXXXX/x86_64_Linux_6X.64/gnu444-g-tp/bin/tool
-encryptPW
test
reached thread null main <-- seem to be exiting before
0
reached thread null
当我有线程时(主线程中没有readLine):
------"Add user"
/home/XXXXX/x86_64_Linux_6X.64/gnu444-g-tp/bin/tool
-encryptPW
aa
0
36Iz05GxD5hlK5OXu7Q_97nJe7Iz05GxD5hlK5OXu7Q_ONg5iRKx7vKST-TrQHo_zFoep0h5iRKx7vKST-TrQHo_zVc
reached thread null
reached thread null
------------start "Change Password"
/home/XXXXX/x86_64_Linux_6X.64/gnu444-g-tp/bin/tool
-encryptPW
ffff
0
reached thread null
reached thread null
-----------start "Change Password"
/home/XXXXXX/x86_64_Linux_6X.64/gnu444-g-tp/bin/tool
-encryptPW
sssaa
0
reached thread null
reached thread null
所以,我想知道我的缓冲读者是否过早退出,或者在读者阅读流之前流程是否退出。我不明白为什么点击“添加用户”似乎有效,而点击“更改密码”按钮不起作用,但两者都使用相同的功能。
非常感谢任何帮助。