Como rodar um programa externo?

Fala galera!

Estou a um tempo utilizando esta classe abaixo para executar um programa .exe externo (feito em pascal) pelo command do Windows, jogar uma entrada neste programa e pegar a saída dele:

[code]package corretor;

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 javax.sound.midi.SysexMessage;
import logica.Constantes;

/**

  • Classe que executa processos externos.
    */
    public class Executador {

    private int exitVal = 0;
    private BufferedReader br = null;
    private String[] args = null;
    private File diretorio = null ;
    private String entrada = null;
    private String saida = null;
    private long tempoExecucao = 0;
    private StreamGobbler outputGobbler = null;
    private static Process proc = null;
    boolean travou = false;

    /**

    • Cria uma nova instância da classe Executador.
    • @param diretorio O diretório padrão que terá o processo.
    • @param args Um vetor de argumentos que serão executados no processo.
    • @param entrada A entrada que o processo terá.
      */
      public Executador(File diretorio, String[] args, String entrada) {
      this.diretorio = diretorio;
      this.args = args;
      this.entrada = entrada;
      }

    /**

    • Executa um determinado processo com os parâmetros passados no construtor.
      */
      public void executar() {
      try {
      Runtime rt = Runtime.getRuntime();
      System.out.println("Setando diretório: " + diretorio.getAbsolutePath());
      String texto = “”;
      for (int i = 0; i <= args.length - 1; i++) {
      texto += args[i] + " ";
      }
      System.out.println(“Executando:” + texto);
      String[] env = new String[] {“PATH=” + System.getenv(“PATH”)};
      proc = rt.exec(args, env, diretorio);

       // alguma mensagem de erro?
       StreamGobbler errorGobbler = new 
           StreamGobbler(proc.getErrorStream(), "ERRO");
      
       // alguma saída?
       outputGobbler = new StreamGobbler(proc.getInputStream(), "SAÍDA");
      
       long tempoInicial = System.currentTimeMillis();
       errorGobbler.start();
       outputGobbler.start();
       
       if (entrada != null) {
           OutputStream out = proc.getOutputStream();
           out.write((entrada).getBytes());
           out.flush();
           out.close();
           
           testarTravamento();
           
           exitVal = proc.waitFor();
           proc.destroy();
           outputGobbler.parar();
           saida = outputGobbler.getSaida();
       } else {
           testarTravamento();
           exitVal = proc.waitFor();
       }
       tempoExecucao = System.currentTimeMillis() - tempoInicial;
        
       System.out.println("Valor de Saída: " + exitVal);
      

      } catch (Throwable t) {
      t.printStackTrace();
      }
      }

    /**

    • Retorna o tempo de execução do processo.
      */
      public long getTempoExecucao() {
      return tempoExecucao;
      }

    /**

    • Retorna a saída do processo.
      */
      public String getSaida() {
      return saida;
      }

    /**

    • Retorna o valor de saída do processo.
      */
      public int getValorSaida() {
      return exitVal;
      }

    private void testarTravamento() {
    travou = false;
    new Thread(new Runnable() {
    public void run() {
    try {
    Thread.currentThread().sleep(Constantes.getTempoMaximoExecucao());
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    if (outputGobbler.isAlive()) {
    travou = true;
    proc.destroy();
    String processo = args[2].substring(0, args[2].length() - 4);
    String[] argsD = new String[] { “cmd”, “/C”, “tskill”, processo};
    Executador exec = new Executador(diretorio, argsD, null);
    exec.executar();
    }
    }
    }).start();
    }

    /**

    • Classe interna utilizada para capturar as saídas e mensagens de erro

    • de um determinado processo.
      */
      class StreamGobbler extends Thread {
      InputStream is = null;
      String type = null;
      String saida = null;
      boolean flagParar = false;

      public void parar() {
      flagParar = true;
      }

      StreamGobbler(InputStream is, String type) {
      this.is = is;
      this.type = type;
      this.saida = new String();
      }

      public void run() {
      try {
      InputStreamReader isr = new InputStreamReader(is);
      br = new BufferedReader(isr);
      String line = null;
      while ( (line = br.readLine()) != null) {
      System.out.println(type + “>” + line);
      if (saida != null) {
      saida += line + “\n”;
      }
      if (flagParar) {
      System.out.flush();
      return;
      }
      }
      } catch (IOException ioe) {
      ioe.printStackTrace();
      }
      }

      /**

      • Retorna a saída do processo.
        */
        public String getSaida() {
        return saida;
        }
        }
        }[/code]

Algumas explicações do código:

Eu executo processos externos por meio desta classe. Quando eu preciso jogar uma entrada no programa é só passar no Construtor uma entrada não nula. Depois de executado eu posso pegar a saída do programa pelo método getSaida() (linha 175).

A Classe interna StreamGobbler serve para ouvir as mensagens que são escritas na saída, que não sejam parte da execução do processo. Normalmente mensagens de erro e de instruções para uso do FPC no meu caso.

O método testarTravamento() (linha 111) serve para estipular um tempo máximo para que o pocesso rode. Caso ele estrapole este limite o processo é encerrado manualmente por meio da execução de outro processo que chama a função “TSKILL” do command do windows.

Um exemplo de utilização desta classe:

[code]
String[] args = new String[] { “cmd”, “/C”, “programa.exe” };
File diretorio = new File(“c:\Programas em Teste”);
String entrada = “1 5 10\nPedro\n9”;

Executador ex = new Executador(diretorio, args, entrada);
ex.executar();
long tempoExecucao = ex.getTempoExecucao();
String saida = ex.getSaida();[/code]

O Problema que eu tenho tido está dentro do trecho de código quando a entrada não é nula! (linha 66), mais especificamente aqui:

OutputStream out = proc.getOutputStream(); out.write((entrada).getBytes()); out.flush(); out.close();

Aqui eu jogo no command do windows a entrada que passo pelo construtor da classe. Porém as vezes funciona corretamente e às vezes não!
O que ocorre é que existem vezes que eu jogo a entrada e a saída vem cortada, incompleta! Percebi isso depois de fazer alguns testes diretamente no command do windows, sem o intermédio do programa.

Alguém pode me ajudar? Alguma idéia?

Pow cara, quando eu li o nome do tópico achei que vc precisasse de ajuda pra rodar.

Eu ia sugerir o JavaRobot mas como vc jah fez tudo direito…

O robot executa comandos, mas não dá retorno.

Não posso te ajudar :wink: nesse caso.

Também não entendi porque com vc não funciona com estabilidade.

O problema está no loop while da classe StreamGobbler.

Tente algo como isso 8)

[code] while (!flagParar) {
if ( (line = br.readLine()) != null){
System.out.println(type + “>” + line);
if (saida != null) {
saida += line + “\n”;
}
}

            }

System.out.flush();[/code]