Java ProcessBuilder 如何从命令获取二进制输出

标签 java processbuilder

我正在尝试使用 ProcessBuilder 执行命令。该命令应该在标准输出上写入二进制数据。如何在我的 byte[] 中获取这些数据?

最佳答案

这是一个工作示例,对于输出 1 返回 true,对于输出 0 返回 false(抛出所有其他情况除外)。我还添加了设置工作路径和环境变量,这对于您的特定示例来说不是必需的,因此您可以将其删除。

  1. 您可以将此代码复制粘贴为类,将其编译为 jar 并运行它。
  2. 已在 WSL Ubuntu 16.04 中验证。
  3. 设置工作目录通过设置binaryCommand[0]="touch";binaryCommand[1]="1";来验证,重新编译并运行 .jar 文件。

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.util.Arrays;
    import java.util.Map;
    import java.util.StringJoiner;
    
    public class GenerateOutput {
    
        /**
         * This code can execute a command and return the binary value of it's output if it 
         * is actually binary.
         * 
         * compile this project into a .jar and run it with for example:
         * java -jar readOutputOfCommand.jar
         * 
         * @param args
         * @throws Exception 
         */
        public static void main(String[] args) throws Exception {
            boolean answerYes = false; // no yes answer to any command prompts is needed.
    
            // to execute a command with spaces in it in terminal, put them in an array of Strings.
            String[] binaryCommand = new String[2];
    
            // write a command that gives a binary output:
            binaryCommand[0] = "echo";
            binaryCommand[1] = "1";
    
            // pass the commands to a method that executes them
            System.out.println("The output of the echo command = "+executeCommands(binaryCommand,answerYes));
        }
    
        /**
         * This executes the commands in terminal. 
         * Additionally it sets an environment variable (not necessary for your particular solution)
         * Additionally it sets a working path (not necessary for your particular solution)
         * @param commandData
         * @param ansYes
         * @throws Exception 
         */
        public static boolean executeCommands(String[] commands,Boolean ansYes) throws Exception {
            String capturedCommandOutput = null;
            System.out.println("Incoming commandData = "+Arrays.deepToString(commands));
            File workingDirectory = new File("/mnt/c/testfolder b/");
    
            // create a ProcessBuilder to execute the commands in
            ProcessBuilder processBuilder = new ProcessBuilder(commands);
    
            // this is not necessary but can be used to set an environment variable for the command
            processBuilder = setEnvironmentVariable(processBuilder); 
    
            // this is not necessary but can be used to set the working directory for the command
            processBuilder.directory(workingDirectory);
    
            // execute the actual commands
            try {
    
                 Process process = processBuilder.start();
    
                 // capture the output stream of the command
                 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                StringJoiner sj = new StringJoiner(System.getProperty("line.separator"));
                reader.lines().iterator().forEachRemaining(sj::add);
                capturedCommandOutput = sj.toString();
                System.out.println("The output of this command ="+ capturedCommandOutput);
    
                 // here you connect the output of your command to any new input, e.g. if you get prompted for `yes`
                 new Thread(new SyncPipe(process.getErrorStream(), System.err)).start();
                 new Thread(new SyncPipe(process.getInputStream(), System.out)).start();
                PrintWriter stdin = new PrintWriter(process.getOutputStream());
    
                //This is not necessary but can be used to answer yes to being prompted
                if (ansYes) {
                    System.out.println("WITH YES!");
                stdin.println("yes");
                }
    
                // write any other commands you want here
    
                stdin.close();
    
                // this lets you know whether the command execution led to an error(!=0), or not (=0).
                int returnCode = process.waitFor();
                System.out.println("Return code = " + returnCode);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            return retrieveBooleanOutput(capturedCommandOutput);
        }
    
        private static boolean retrieveBooleanOutput(String commandOutput) throws Exception {
            if (commandOutput != null && commandOutput.length() == 1) { 
                if (commandOutput.contains("0")) {
                    return false;
                } else if (commandOutput.contains("1")) {
                    return true;
                }
            }
            throw new Exception("The output is not binary.");
        }
    
        /**
         * source: https://stackoverflow.com/questions/7369664/using-export-in-java
         * @param processBuilder
         * @param varName
         * @param varContent
         * @return
         */
        private static ProcessBuilder setEnvironmentVariable(ProcessBuilder processBuilder){
            String varName = "variableName";
            String varContent = "/mnt/c/testfolder a/";
    
            Map<String, String> env = processBuilder.environment();
             System.out.println("Setting environment variable "+varName+"="+varContent);
             env.put(varName, varContent);
    
             processBuilder.environment().put(varName, varContent);
    
             return processBuilder;
        }
    }
    
    
    class SyncPipe implements Runnable
    {   
        /**
         * This class pipes the output of your command to any new input you generated
         * with stdin. For example, suppose you run cp /mnt/c/a.txt /mnt/b/
         * but for some reason you are prompted: "do you really want to copy there yes/no?
         * then you can answer yes since your input is piped to the output of your
         * original command. (At least that is my practical interpretation might be wrong.)
         * @param istrm
         * @param ostrm
         */
        public SyncPipe(InputStream istrm, OutputStream ostrm) {
            istrm_ = istrm;
            ostrm_ = ostrm;
        }
        public void run() {
    
          try
          {
              final byte[] buffer = new byte[1024];
              for (int length = 0; (length = istrm_.read(buffer)) != -1; )
              {
                  ostrm_.write(buffer, 0, length);                
                  }
              }
              catch (Exception e)
              {
                  e.printStackTrace();
              }
          }
          private final OutputStream ostrm_;
          private final InputStream istrm_;
    }
    

关于Java ProcessBuilder 如何从命令获取二进制输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25238013/

相关文章:

java - 如果重新排列两个字符串,如何比较它们

java - 使用SSL连接在java中连接到mySQL数据库

java - 在 pmd 中排除不起作用

Java ProcessBuilder 在传递参数时使用字符串中的句点而不是斜杠

java - 如何测试基于 jline 的控制台应用程序

java - Android Market Licensing (LVL) 始终返回 RETRY

java - 关于 basicLTI java 实现 (basiclti-util-java),¿文档?

java - 使用 ProcessBuilder 运行 ImageMagick 命令

java - 如何将 ProcessBuilder 的输出重定向到字符串?

java:ProcessBuilder 占用大量内存