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

获取Java中字符串的命令提示符输出,java,tostring,command-prompt,outputstream,Java,Tostring,Command Prompt,Outputstream,我需要一个java方法,该方法将读取命令提示符输出并将其存储到字符串中以读入java 到目前为止,这是我所拥有的,但不起作用 public void testGetOutput() { System.out.println("\n\n****This is the testGetOutput Method!****"); String s = null; String query = "dir " + this.desktop; try { Run

我需要一个java方法,该方法将读取命令提示符输出并将其存储到字符串中以读入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的scan 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'
哦,顺便说一句,当我在常规命令提示符下运行该查询时,它完全按照我的要求执行,提供了我迫切需要的所有输出

这是最初的问题(我不知道如何重新提交问题):

我到处找都找不到。我不确定我的发现是否与我想做的事情有关。我还没有太多的代码,所以在这里放代码没什么用,我认为这应该很简单,所以我将在这里给出一些截图。所以我的任务是:

  • 扫描满是翻录DVD文件夹(包含VOB文件的视频文件夹等)的文件夹,并将这些文件夹名称存储为DVD的标题

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

  • Regex用于标识每个标题、章节和语言的字符串

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

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

  • 我唯一不确定的是第二步!我可以很容易地做任何事情。我读过很多关于OutputStreams的书,但我似乎不明白它是如何工作的。我真的只需要得到一个字符串的输出,我可以用正则表达式来得到我需要的东西。以下是我需要输入的内容和需要从输出中删除的内容的屏幕截图:

    HandBrakeCLI的输入:

    要扫描的输出:


    假设您使用
    Runtime.exec()
    启动外部进程,给您一个
    进程
    对象,该对象上有三个相关方法:
    getOutputStream()
    getInputStream()
    getErrorStream()

    我认为很容易对这些产生混淆——您可能认为您希望看到流程的输出,因此“输出流”就是您想要的。但您需要记住的是,这些对象的命名是从Java代码的角度进行的——OutputStream是Java用来写入输出的,而InputStream是Java用来读取输入的。从Java的角度来看,外部进程的输出就是输入


    因此,您可以使用
    getInputStream()
    并对其返回的
    InputStream
    调用适当的方法来读取输出。您可能还想使用
    getErrorStream()
    确保不会因为写入标准错误而丢失任何内容。

    首先,您需要一种非阻塞方式来读取
    standard.out
    standard.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();
        }
    }
    
    然后需要将此类绑定到相应的
    InputStream
    OutputStream
    对象中

        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中的任何东西时,这几乎就是我使用的锅炉板

    更高级的方法是使用
    FutureTask
    Callable
    或至少
    Runnable
    而不是直接扩展
    线程
    ,这不是最佳做法

    注意:

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

    <dependency>
      <groupId>com.google.code.findbugs</groupId>
      <artifactId>jsr305</artifactId>
      <version>1.3.9</version>
    </dependency>
    
    
    com.google.code.findbugs
    jsr305
    1.3.9
    
    这个完整的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
    
    D:\projects\eric\eclipseworkspace\testing2目录 2012年5月7日下午1:06。 2012年5月7日下午1:06。。 2012年5月6日上午11:11 301.课堂路径 2012年5月6日上午11:11 384.项目 2012年5月6日上午11:11设置 2012年5月7日下午1:42 2012年5月6日上午11:11 src 2012年5月7日01:06下午2285 usernames.txt 3个文件2970字节 5个目录45884035072字节可用 完成
    感谢您的澄清!这有点让人困惑。我现在面临的问题不是打印查询结果(如第二个屏幕截图所示),而是打印查询本身。代码中的内容太多,无法添加到此处的注释中,因此这里有一个指向collabedit文档的链接:我认为,一个问题是
    exec()
    需要一个实际的可执行文件--批处理文件不是一个可执行程序,它是由Windows shell执行的一系列命令。看,我们真的很接近了!所以现在我的问题是我的缓冲读取器对象为null。我不知道为什么。我已经更新了collabedit文档上的代码。您会注意到我将println放在commandResult的周围,因为这是代码暂停的地方,当commandResult.readLine()应该等于第一个输入行时(或者至少,这是我要查找的)。再次感谢你的帮助!啊,我认为p