Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > getRuntime().exec и потоки


Автор: Demetrio 1.5.2007, 09:46
Новичок в java
далее
Как правильно обеспечить удерживание процесса(или сессии)?
На данный момент делаю так, но ...
1. Второй раз вызов метода get_info ничего не вовзращает..... где накосячил?
2. Как мне очистить OutPutStream , так как мой mytelnet при старте выдает служебную информацию....

p.s. Конечно mytelnet не telnet никакой... просто консольная клиентская утилитка. Можно в ней затык.

Код

public class mytelnet 
{
    private Process proc;
    
    public mytelnet(String id_user, String password)  throws IOException
    {
             String pre_command = "mytelnet -id=admin -pa=admin";
        proc = Runtime.getRuntime().exec(pre_command);
    }
    
    public String get_info(String command) throws IOException
    {
        BufferedWriter buffOut = new BufferedWriter( new OutputStreamWriter(proc.getOutputStream()) ); 
        buffOut.write(command);
        buffOut.close();
        
        InputStream inputstream = proc.getInputStream();
        InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
        BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
    
        String line;
        String linea = new String();
        while ((line = bufferedreader.readLine()) != null)
        {
            linea += line+"\n";
        }
        return linea;
    }
}



Автор: LSD 1.5.2007, 14:43
Цитата(Demetrio @  1.5.2007,  10:46 Найти цитируемый пост)
1. Второй раз вызов метода get_info ничего не вовзращает..... где накосячил?

Зачем ты закрываешь поток (buffOut.close();)? Не ты его открывал, не тебе его и закрывать.

Цитата(Demetrio @  1.5.2007,  10:46 Найти цитируемый пост)
2. Как мне очистить OutPutStream , так как мой mytelnet при старте выдает служебную информацию....

Просто прочитать ее из process InputStream.

Автор: Demetrio 1.5.2007, 16:38
Без закрытия close ничего не выводит вовсе.... может еще как надо подкрректировать...

НЕмного модернизировал под ProcessBuilder, но сути это не меняет...
Если у кого есть пример, как посылать команды открытому процессу по мере необходимости, не вызывая ProcessBuilder каждый раз, то с радостью воспользуюсь....
Еще раз повторюсь первый вызов метода get_info проходит на ура
Код


public class mytelnet
{
    private Process proc;
    private InputStream inputstream;
    private OutputStream outputstream;
    
    public mytelnet(String id_user, String password)  throws IOException
    {        
        this.proc = new ProcessBuilder("bash").start();                
        this.inputstream = this.proc.getInputStream();
        this.outputstream = this.proc.getOutputStream();        
    }
    
    public String get_info(String command) throws IOException
    {
        String line;
        String linea = new String();
        
        BufferedWriter buffOut = new BufferedWriter( new OutputStreamWriter(this.outputstream) );
        buffOut.write("pwd");
        buffOut.close();
                
        InputStreamReader inputstreamreader = new InputStreamReader(this.inputstream);
        BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
         
        while ((line = bufferedreader.readLine()) != null)
        {
            linea += line+"\n";
        }
        return linea;
    }
}



Автор: powerOn 1.5.2007, 16:48
Модератор: Используйте кнопку КОД для оформления исходников!

Автор: LSD 1.5.2007, 17:37
Цитата(Demetrio @  1.5.2007,  17:38 Найти цитируемый пост)
Без закрытия close ничего не выводит вовсе.... может еще как надо подкрректировать...

Используй вместо close() - flush().

Автор: Demetrio 2.5.2007, 09:26
нет, данный вариант тоже не проходит

Автор: LSD 3.5.2007, 11:08
Код
public class CmdTest
{
  private InputStream inputStream;
  private OutputStream outputStream;
  private InputStream errorStream;
  private Process proc;

  public CmdTest() throws IOException
  {
    proc = new ProcessBuilder("cmd.exe").start();
    this.inputStream = proc.getInputStream();
    this.outputStream = proc.getOutputStream();
    this.errorStream = proc.getErrorStream();
  }

  public void exec(String... commands)
  {
    new Spooler(inputStream, System.out).start();
    new Spooler(errorStream, System.err).start();

    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(this.outputStream));
    for(String command : commands)
    {
      try
      {
        writer.write(command);
        writer.newLine();
        writer.flush();
      }
      catch(IOException e)
      {
        e.printStackTrace();
      }
    }
  }

  public int exit()
  {
    try
    {
      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(this.outputStream));
      writer.write("exit");
      writer.newLine();
      writer.flush();
      return proc.waitFor();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
    return -1;
  }

  public static void main(String[] args) throws IOException
  {
    CmdTest test = new CmdTest();
    test.exec("C:", "CD C:\\Windows", "dir");
    test.exit();
  }

  private static class Spooler extends Thread
  {
    private InputStream in;
    private OutputStream out;


    public Spooler(InputStream in, OutputStream out)
    {
      super("SpoolerThread");
      this.in = in;
      this.out = out;
    }

    @Override
    public void run()
    {
      byte[] buffer = new byte[1024];
      int read;
      try
      {
        while((read = in.read(buffer)) != -1)
          out.write(buffer, 0, read);
      }
      catch(IOException e)
      {
        e.printStackTrace();
      }
    }
  }
}

Автор: Akeem 13.2.2008, 11:05
Вопрос по классу CmdTest.
Как можно переписать этот класс так чтобы результаты выводились не на консоль, а в в стринг.
Или плиз покажите строчку где выводятся результаты работы команды. 

Сорри. Смотрю я на класс и не вижу где эти результаты выводятся. :-[

Автор: Sardar 13.2.2008, 12:32
Spooler перегоняет данные из input- в output-stream, тредом висит, блокируется по in.read(). Пока есть данные в потоке тред разблокирован, зачитывает их в переданный output-stream (81-82). Рядом с out.write поставь StringBuilder.append(buffer, 0, read). Если необходимо, то по in.available() > 0 можно определить заблокируемся ли на следующей итерации.

Автор: Akeem 13.2.2008, 12:53
прописал строку StringBuilder.append(buffer, 0, read)  перед out.write. И еклипс начал ругатся на buffer
Пишет что нужно чтобы он был CharSequence

А если использовать замисть переганяния StringBufferInputStream он вроде сражу должен возвращать нужный стринг.

Добавлено через 10 минут и 30 секунд
Решил проблему. 
Код


 public void run()
    {
      char[] buffer = new char[1024];
      int read;
     
      try
      {
       InputStreamReader br = new InputStreamReader(in);
       StringBuilder sB = new StringBuilder();
        while((read = br.read(buffer)) != -1)
        {
         
         sB.append(buffer, 0, read); //Пихаем наш буфер в стринг.
        }
       
      }
      catch(IOException e)
      {
        e.printStackTrace();
      }
      
    }


Теперь у меня возник вопрос такой.
Возможен ли вывод каждого выполнения команды отдельно. 
Например выполнил одну команду вывел её результат. И как это сделать?
П.С. Последовательный вывод возможен для одной консоли. smile

Автор: LSD 13.2.2008, 13:23
Вместо:
Код

new Spooler(inputStream, System.out).start();
new Spooler(errorStream, System.err).start();

пиши:
Код

ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
ByteArrayOutputStream err = new ByteArrayOutputStream(1024);
new Spooler(inputStream, out).start();
new Spooler(errorStream, err).start();

а когда хочешь получить строку:
Код

String output = new String(out.toByteArray());
String errors = new String(err.toByteArray());

Автор: Akeem 13.2.2008, 13:37
Цитата(LSD)

а когда хочешь получить строку:
 Java

String output = new String(out.toByteArray());
String errors = new String(err.toByteArray());



Куда мне это добавить? В функцию exec?  

П.С. Я добавил ее в эту функцию. но мне после выполнения команды например: test.exec("C:"); test.exec("CD"); выдает [] 

Автор: LSD 13.2.2008, 13:42
Цитата(Akeem @  13.2.2008,  13:37 Найти цитируемый пост)
Куда мне это добавить? В функцию exec?  

Туда где тебе надо получить результат выполнения команды.

Автор: Akeem 13.2.2008, 13:52
Вот написал метод для вывода результатов
Код


 public String GetReslut() 
  {
      String output = new String(out.toByteArray());  //переменные обьявлены как глобальные в классе
        String errors = new String(err.toByteArray());
    return output+"\n"+errors;
  } 


Результат выполнения команд 
Код

Cmd test = new Cmd();
test.exec("C:"); 
test.exec("CD");
System.out.println(test.GetReslut());


Остается плачевным -- те выводит пустую консоль. Замисть того чтобы вывести C:\

Добавлено через 2 минуты и 11 секунд
П.С. Сорри за тупые вопросы. Чет туплю седня.  smile 

Автор: Akeem 13.2.2008, 14:17
Вот как нужно выводить результат каждой команды:
Функция для перехвата вывода:
Код


public void run()
    {
      char[] buffer = new char[1024];
      int read;
     
      try
      {
       InputStreamReader br = new InputStreamReader(in);
       
        while((read = br.read(buffer)) != -1)
        {
         
         sB.append(buffer, 0, read);

        }
       
      }
      catch(IOException e)
      {
        e.printStackTrace();
      }
      
    }

(генетически модифицированая функция написаная ЛСД (спасибо ему за это огромное)  smile )
Функция вывода:
Код

public StringBuilder GetReslut() 
  {

    return Spooler.sB;
  }



Вызов:
Код

Cmd test = new Cmd();
test.exec("C:"); 
test.exec("CD");
System.out.println(test.GetReslut());


Единственный минус не понятно каким Р оно работает.  
Те при дебаге все работает как нужно, но при обычном выполнении ничего не выводится.

Автор: LSD 13.2.2008, 14:44
Проблема состоит в том, что CmdTest.exec() не ждет пока будет выполнена команда. Команда просто передаётся cmd.exe и все. Сколько она будет выполняться - неизвестно. С выводом в System.out таких проблем нет, потому что по мере выполнения команды данные перекачиваются в System.out, а тут ты сам должен определить когда команда выполнилась, или просто подождать.

Код

import java.io.*;

public class CmdTest
{
  private OutputStream outputStream;
  private InputStream inputStream;
  private InputStream errorStream;
  private ByteArrayOutputStream output = new ByteArrayOutputStream();
  private ByteArrayOutputStream errors = new ByteArrayOutputStream();
  private Process proc;

  public CmdTest() throws IOException
  {
    proc = new ProcessBuilder("cmd.exe").start();
    this.inputStream = proc.getInputStream();
    this.outputStream = proc.getOutputStream();
    this.errorStream = proc.getErrorStream();

    new CmdTest.Spooler(inputStream, output).start();
    new CmdTest.Spooler(errorStream, errors).start();
  }

  public void exec(String... commands)
  {
    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(this.outputStream));
    for(String command : commands)
    {
      try
      {
        writer.write(command);
        writer.newLine();
        writer.flush();
      }
      catch(IOException e)
      {
        e.printStackTrace();
      }
    }
  }

  public String getOutput(String charset) throws UnsupportedEncodingException
  {
    return new String(output.toByteArray(), charset);
  }

  public void clearOutput()
  {
    output.reset();
  }

  public String getErrors(String charset) throws UnsupportedEncodingException
  {
    return new String(errors.toByteArray(), charset);
  }

  public void clearErrors()
  {
    errors.reset();
  }

  public int exit()
  {
    try
    {
      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(this.outputStream));
      writer.write("exit");
      writer.newLine();
      writer.flush();
      return proc.waitFor();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
    return -1;
  }

  public static void main(String[] args) throws Exception
  {
    CmdTest test = new CmdTest();

    test.exec("C:", "CD C:\\Windows", "dir");
    Thread.sleep(1000);
    System.out.println("output = " + test.getOutput("Cp866"));
    test.clearOutput();
    System.out.println("errors = " + test.getErrors("Cp866"));
    test.clearErrors();
    System.out.println("\n=======================================\n");

    test.exec("ipconfig");
    Thread.sleep(1000);
    System.out.println("output = " + test.getOutput("Cp1251"));
    test.clearOutput();
    System.out.println("errors = " + test.getErrors("Cp1251"));
    test.clearErrors();
    System.out.println("\n=======================================\n");

    test.exec("find /?");
    Thread.sleep(1000);
    System.out.println("output = " + test.getOutput("Cp866"));
    test.clearOutput();
    System.out.println("errors = " + test.getErrors("Cp866"));
    test.clearErrors();
    System.out.println("\n=======================================\n");

    test.exit();
    Thread.sleep(1000);
    System.out.println("output = " + test.getOutput("Cp866"));
    test.clearOutput();
    System.out.println("errors = " + test.getErrors("Cp866"));
    test.clearErrors();
    System.out.println("\n=======================================\n");
  }

  private static class Spooler extends Thread
  {
    private InputStream in;
    private OutputStream out;

    public Spooler(InputStream in, OutputStream out)
    {
      super("SpoolerThread");
      this.in = in;
      this.out = out;
    }

    @Override
    public void run()
    {
      byte[] buffer = new byte[1024];
      int read;
      try
      {
        while((read = in.read(buffer)) != -1)
          out.write(buffer, 0, read);
      }
      catch(IOException e)
      {
        e.printStackTrace();
      }
    }
  }
}

Автор: Akeem 13.2.2008, 15:15
LSD, спасибо!
Все работает. Премного благодарен. 

Только вопрос: обезательно указывать кодировку? спрашиваю потому що если указать явно то выдает ошибку что неопознает кодировки. (мне не нужны лишние параметры)

П.С. Код переписал под свою программу. 


Автор: LSD 13.2.2008, 15:22
Цитата(Akeem @  13.2.2008,  15:15 Найти цитируемый пост)
Только вопрос: обезательно указывать кодировку?

У меня без указания кодировки не все работает корректно, вместо русских буквы кракозябры. Можешь переписать так:
Код

  public String getOutput(Charset charset)
  {
    return new String(output.toByteArray(), charset);
  }

тогда никаких Exception-ов выкидываться не будет.

Добавлено через 37 секунд
К тому же часть команд выводит данные в 866 кодировке, часть в 1251.

Автор: Akeem 13.2.2008, 15:26
Ну в принципе у меня проблем с кодировкой не должно быть. Все результаты и команды на англ. 

П.С. Я вообще убрал объявление кодировки с функции.
Код

public String getOutput()
  {
    return new String(output.toByteArray());
  }

Автор: Resilient 27.11.2008, 18:21
Приветствую... вобщем-то тоже чайник в Яве, надеюсь, что только пока что smile
А нету ли способа гарантированно дождаться выполнения команды? и узнать, что вернула та програмка.

Автор: LSD 29.11.2008, 15:37
Цитата(Resilient @  27.11.2008,  18:21 Найти цитируемый пост)
А нету ли способа гарантированно дождаться выполнения команды? и узнать, что вернула та програмка.

А нафига?
Если тебе нужно выполнить некую программу, то вызывай непосредственно её, а не через cmd.exe и таких проблем не будет. А если тебе нужно выполнить команду именно cmd.exe, то в любом случае ты будешь парсить вывод этой команды и по нему уже можно будет определить, что команда завершена.

Автор: Resilient 1.12.2008, 16:52
В данном случае неизвестно других методов вызова, кроме как из командной строки :(
Нужно же дождаться окончания выполнения и в зависимости от кода возврата в cmd продолжить.

Автор: LSD 1.12.2008, 18:23
Цитата(Resilient @  1.12.2008,  16:52 Найти цитируемый пост)
В данном случае неизвестно других методов вызова, кроме как из командной строки :(

Вызова чего? Ты программу пытаешься вызвать или внутреннюю команду cmd.exe?

Автор: Resilient 2.12.2008, 15:11
программу. И другого вызова в данном случае не получится.
НО у меня оно дожидается окончания работы. smile

Автор: LSD 2.12.2008, 17:33
Цитата(Resilient @  2.12.2008,  15:11 Найти цитируемый пост)
программу.

Ну так и запускай программу, а не cmd.exe smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)