Получить вывод командной строки в строку в Java - PullRequest
8 голосов
/ 03 октября 2011

Мне нужен метод 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 работает под окном cmd, которое запускается под моей IDE. Все это имеет смысл, но HandBrakeCLI.exe не завершается, поэтому я предполагаю, что поэтому не могу прочитать вывод как ввод для моей программы.

Итак, после этого фона. Мой большой вопрос заключается в следующем: как заставить HandBrakeCLI.exe закрыться после завершения моего запроса, чтобы я мог получить его вывод? Просто для дополнительной информации, единственное различие между методом выше и методом сканирования DVD, который я имею для HandBrakeCLI, заключается в том, что переменная запроса отличается. Как этот пример:

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 (папки Video_TS с файлами VOB и т. Д.), И сохраните имена этих папок в качестве названия DVD.

  2. Сканирование каждой папки с помощью HandBrakeCLI и сохранение вывода в строку.

  3. Пересмотрите строку, чтобы указать каждый заголовок, главу и язык.

  4. Генерация запросов для возврата в HandBrakeCLI для массового кодирования каждого языка в каждой главе в каждом заголовке для каждого DVD (вы можете понять, почему я хочу автоматизировать это!)

  5. Сохранить эти запросы в * .bat файле

Единственная часть, в которой я не уверен, это шаг 2! Я могу сделать все остальное довольно легко. Я много читал о OutputStreams, но я просто не могу понять, как он работает. Мне действительно просто нужно получить вывод в строку, которую я могу регулярное выражение, чтобы получить вещи, которые мне нужны Вот скриншоты того, что мне нужно ввести и что мне нужно убрать с вывода:

Вход для HandBrakeCLI:

enter image description here

Вывод на сканирование:

enter image description here

Ответы [ 3 ]

6 голосов
/ 05 июля 2012

Этот полный пример программы на 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
5 голосов
/ 11 октября 2011

Для начала вам нужен неблокирующий способ чтения из 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 вместо прямого расширения Thread, что не является наилучшей практикой.

Примечание:

Аннотации @Nonnull находятся в библиотеке JSR305. Если вы используете Maven, и вы используете Maven, не так ли, просто добавьте эту зависимость к своему pom.xml.

<dependency>
  <groupId>com.google.code.findbugs</groupId>
  <artifactId>jsr305</artifactId>
  <version>1.3.9</version>
</dependency>
1 голос
/ 03 октября 2011

Если вы используете Runtime.exec() для запуска внешнего процесса, давая вам объект Process, для этого объекта есть три соответствующих метода: getOutputStream(), getInputStream() и getErrorStream().

Я думаю, что легко запутаться в этом - вы, вероятно, думаете, что хотите увидеть выходные данные процесса, поэтому «поток вывода» - это то, что вам нужно. Но нужно помнить, что именование этих объектов происходит с точки зрения Java-кода - OutputStream предназначен для Java для записи вывода, а InputStream - для Java для чтения ввода. Вывод вашего внешнего процесса, с точки зрения Java, является вводом.

Таким образом, вы должны использовать getInputStream() и вызывать соответствующие методы для InputStream, возвращаемого им, чтобы прочитать вывод. Вы также можете использовать getErrorStream(), чтобы убедиться, что вы ничего не пропустили, потому что это записано со стандартной ошибкой.

...