Java从外部进程获取stdOut - 获得间歇性结果

时间:2015-12-09 00:17:53

标签: java process stdout

在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

所以,我想知道我的缓冲读者是否过早退出,或者在读者阅读流之前流程是否退出。我不明白为什么点击“添加用户”似乎有效,而点击“更改密码”按钮不起作用,但两者都使用相同的功能。

非常感谢任何帮助。

0 个答案:

没有答案