在Java中获取命令提示输出到字符串

时间:2011-10-03 15:43:06

标签: java tostring command-prompt outputstream

我需要一个java方法来读取命令提示输出并将其存储到String中以便读入Java。

这是我到目前为止所做的,但是效果不正确。

public void testGetOutput() {
    System.out.println("\n\n****This is the testGetOutput Method!****");
    String s = null;
    String query = "dir " + this.desktop;
    try {
        Runtime runtime = Runtime.getRuntime();
        InputStream input = runtime.exec("cmd /c " + query).getInputStream();
        BufferedInputStream buffer = new BufferedInputStream(input);
        BufferedReader commandResult = new BufferedReader(new InputStreamReader(buffer));
        String line = "";
        try {
            while ((line = commandResult.readLine()) != null) {
                s += line + "\n";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(s);
    } catch (Exception e) {
        e.printStackTrace();
    }
}//end testGetOutput()

我认为问题是当我尝试将查询更改为将执行HandBrakeCLI.exe的命令时。在程序运行时查看我的系统(但似乎已暂停),它向我显示HandBrakeCLI.exe正在我的IDE下运行的cmd窗口下运行。所有这些都是有道理的,但是HandBrakeCLI.exe没有退出,所以我猜这就是为什么我无法将输出读作我程序的输入。

所以,在那个背景之后。我的一个大问题是:在完成查询后如何让HandBrakeCLI.exe关闭以便我可以得到它的输出? 仅仅为了额外的信息,上面的方法与我对HandBrakeCLI的扫描DVD方法的唯一区别是查询变量是不同的。像这个例子:

String query = "C:\Users\Kent\Desktop\HBCLI\HandBrakeCLI -t --scan -i "C:\Users\Kent\Desktop\General Conference DVDs\Sources\174th October 2004\DVD 1"; //this is actually a variable in the DVD object, but here's an example'

哦,顺便说一句,当我在常规命令提示符下运行该查询时,它完全符合我的要求,为我提供了我迫切渴望的所有输出!

这是原始问题(我不确定如何重新提交问题):

我一直在寻找各处,无法弄清楚这一点。我不确定我发现的东西与我想做的事情有关。我还没有很多代码,所以在这里放置代码并没有太大的作用,我认为这应该很简单,所以我将在这里给出一些截图。所以这是我的任务:

  1. 扫描已翻录的DVD文件夹(带有VOB文件的Video_TS文件夹等)的文件夹,并将这些文件夹名称存储为DVD的标题。

  2. 使用HandBrakeCLI扫描每个文件夹并将输出存储到字符串中。

  3. 正则表达字符串以标识每个标题,章节和语言。

  4. 生成查询以回馈HandBrakeCLI,对每张DVD的每个标题中的每一章中的每种语言进行批量编码(您可以看到我为什么要自动执行此操作!)

  5. 将这些查询存储在* .bat文件

  6. 我唯一不确定的部分是第2步!我可以很容易地做其他事情。我已经阅读了很多关于OutputStreams的内容,但我似乎无法理解它是如何工作的。我真的只需要输出一个字符串,我可以正则表达式来获取我需要的东西。以下是我需要输入的内容以及我需要从输出中删除的内容的屏幕截图:

    输入HandBrakeCLI:

    enter image description here

    输出扫描:

    enter image description here

3 个答案:

答案 0 :(得分:6)

这个完整的Java程序示例在命令行上运行命令'dir'(目录列表),并将结果拉入字符串并将其打印在控制台上。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class X {
    public static void main(String[] args) {
        try{
            String command = "dir";
            String s = get_commandline_results(command);
            System.out.println(s);
        }
        catch(Exception e){
            e.printStackTrace();
        }
        System.out.println("done");
    }

    public static String get_commandline_results(String cmd)
        throws IOException, InterruptedException, IllegalCommandException{

        //Do not remove the authorizedCommand method.  Be prepared 
        //to lose your hard drive if you have not white-listed the 
        //commands that can run.
        if (!authorizedCommand(cmd)) 
            throw new IllegalCommandException();

        String result = "";
        final Process p = Runtime.getRuntime().
            exec(String.format("cmd /c %s", cmd));
        final ProcessResultReader stderr = new ProcessResultReader(
                p.getErrorStream(), "STDERR");
        final ProcessResultReader stdout = new ProcessResultReader(
                p.getInputStream(), "STDOUT");
        stderr.start();
        stdout.start();
        final int exitValue = p.waitFor();
        if (exitValue == 0){
            result = stdout.toString();
        }
        else{
            result = stderr.toString();
        }
        return result;
    }
    public static boolean authorizedCommand(String cmd){
        //Do not allow any command to be run except for the ones 
        //that we have pre-approved here.  This lessens the 
        //likelihood that fat fingers will wreck your computer.
        if (cmd.equals("dir"))
            return true;
        //add the commands you want to authorize here.

        return false;
    }
}

class ProcessResultReader extends Thread{
    final InputStream is;
    final String type;
    final StringBuilder sb;

    ProcessResultReader(final InputStream is, String type){
        this.is = is;
        this.type = type;
        this.sb = new StringBuilder();
    }

    public void run()
    {
        try{
            final InputStreamReader isr = new InputStreamReader(is);
            final BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null)
            {
                this.sb.append(line).append("\n");
            }
        }
        catch (final IOException ioe)
        {
            System.err.println(ioe.getMessage());
            throw new RuntimeException(ioe);
        }
    }
    @Override
    public String toString()
    {
        return this.sb.toString();
    }
}
class IllegalCommandException extends Exception{
    private static final long serialVersionUID = 1L;
    public IllegalCommandException(){   }
}

在Windows上,这是我得到的结果

Directory of D:\projects\eric\eclipseworkspace\testing2
07/05/2012  01:06 PM    <DIR>          .
07/05/2012  01:06 PM    <DIR>          ..
06/05/2012  11:11 AM               301 .classpath
06/05/2012  11:11 AM               384 .project
06/05/2012  11:11 AM    <DIR>          .settings
07/05/2012  01:42 PM    <DIR>          bin
06/05/2012  11:11 AM    <DIR>          src
07/05/2012  01:06 PM             2,285 usernames.txt
               3 File(s)          2,970 bytes
               5 Dir(s)  45,884,035,072 bytes free

done

答案 1 :(得分:5)

首先,您需要采用非阻止方式来阅读Standard.outStandard.err

private class ProcessResultReader extends Thread
{
    final InputStream is;
    final String type;
    final StringBuilder sb;

    ProcessResultReader(@Nonnull final InputStream is, @Nonnull String type)
    {
        this.is = is;
        this.type = type;
        this.sb = new StringBuilder();
    }

    public void run()
    {
        try
        {
            final InputStreamReader isr = new InputStreamReader(is);
            final BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null)
            {
                this.sb.append(line).append("\n");
            }
        }
        catch (final IOException ioe)
        {
            System.err.println(ioe.getMessage());
            throw new RuntimeException(ioe);
        }
    }

    @Override
    public String toString()
    {
        return this.sb.toString();
    }
}

然后,您需要将此类绑定到相应的InputStreamOutputStream对象。

    try
    {
        final Process p = Runtime.getRuntime().exec(String.format("cmd /c %s", query));
        final ProcessResultReader stderr = new ProcessResultReader(p.getErrorStream(), "STDERR");
        final ProcessResultReader stdout = new ProcessResultReader(p.getInputStream(), "STDOUT");
        stderr.start();
        stdout.start();
        final int exitValue = p.waitFor();
        if (exitValue == 0)
        {
            System.out.print(stdout.toString());
        }
        else
        {
            System.err.print(stderr.toString());
        }
    }
    catch (final IOException e)
    {
        throw new RuntimeException(e);
    }
    catch (final InterruptedException e)
    {
        throw new RuntimeException(e);
    }

当我需要Runtime.exec() Java中的任何内容时,这几乎就是我使用的样板。

更高级的方法是使用FutureTaskCallable或至少Runnable,而不是直接扩展Thread,这不是最佳做法。

注意:

@Nonnull注释位于JSR305库中。如果您正在使用Maven,并且您使用Maven不是您,只需将此依赖项添加到pom.xml

<dependency>
  <groupId>com.google.code.findbugs</groupId>
  <artifactId>jsr305</artifactId>
  <version>1.3.9</version>
</dependency>

答案 2 :(得分:1)

假设您使用Runtime.exec()启动外部流程,并为您提供Process个对象,则该对象有三种相关方法:getOutputStream()getInputStream()和{ {1}}。

我认为很容易对这些感到困惑 - 你可能认为你想看到进程的输出,因此你想要的是“输出流”。但是你需要记住的是,这些对象的命名来自Java代码的角度 - 一个OutputStream用于Java写入输出,而InputStream用于Java来读取输入。从Java的角度来看,外部进程的输出是输入。

因此,您将使用getErrorStream()并在其返回的getInputStream()上调用适当的方法来读取输出。您也可能希望使用InputStream来确保您没有遗漏任何内容,因为它被写入标准错误。