Process.waitFor() trava no windows

Pessoal… fiz uma aplicacao no linux e esta rodando normalmente… porem fui testar no windows… quando faco o comando Process.waitFor() ele trava … so com ctrl+al+del e matando a aplicacao…

Alguem pode me explicar? como contornar isso?

.
.
.
.
Runtime run = Runtime.getRuntime();
Process process=run.exec(teste);
process.waitFor();
.
.
.

Obrigada

Olá

Seria melhor se você colocasse um trecho maior de código para que a gente soubesse se tem I/O na parada. Mas de qualquer jeito há coisas que você precisa saber:

[quote=javadoc] The methods that create processes may not work well for special processes on certain native platforms, such as native windowing processes, daemon processes, Win16/DOS processes on Microsoft Windows, or shell scripts. The created subprocess does not have its own terminal or console. All its standard io (i.e. stdin, stdout, stderr) operations will be redirected to the parent process through three streams (getOutputStream(), getInputStream(), getErrorStream()). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.

The subprocess is not killed when there are no more references to the Process object, but rather the subprocess continues executing asynchronously. [/quote]

Leia também http://www.javaworld.com/cgi-bin/mailto/x_java.cgi

[]s
Luca

Ola Luca… :smiley:
Entao… meu teste é um programa em C que gera um TXT … o pq deu estar usando o waitFor() é pq quero que termine a execucao para depois eu ler esse meu TXT… se eu tiro esse waitFor ele passa direto para outra tarefa… e nao acha o arquivo… pq ele vai ler esse arquivo…

Eu fiz uma telinha em SWING para achar o arquivo e apartir desse arquivo eu rodo o programa em C e gero o TXT…

entao esse exec(teste) pega o arquivo q eu entrei e gera o TXT…

Como eu poderia resolver isso sem precisar usar o waitFor()?

Obrigada

bom–>
eu coloquei new PrintStream(process.getInputStream()).start();
process.waitFor();
e funcionou…

porem…

eu Faco isso para Ler o Arquivo de saida:

 try{
                 
                        
                        FileInputStream fi=new FileInputStream(arq_out);
                        BufferedReader br=new BufferedReader(new InputStreamReader(fi));
                        String string=br.readLine();
                        
                        while(string != null)
                        {
                            textArea1.append(string + "\n");
                            string = br.readLine();
                        }
                        br.close();
                        fi.close();
                      
                        }
                    catch(java.io.IOException e)
                    {
                     
                         JOptionPane.showMessageDialog( null, "Erro ao Abrir o Arquivo: " + e.toString() );
                     
                    }
                    catch(Exception ex)
                    {
                
                    }

O que acontece ele vai imprimindo Linha por Linha no meu TextArea… como faco para imprimir Tudo de uma vez?? :smiley:

Obrigada

O Windows bloqueia a execução até que a saída do programa tenha sido lida pelo aplicativo que o chamou.

É meio ridículo, mas crie uma segunda thread que fica lendo a saída do processo e esse problema deve parar de acontecer.

Aqui, usamos a seguinte classe para redirecionar o outputStream do processo para alguma saída de console:

[code]import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class StreamRedirector {
private OutputStream out;
private InputStream in;

private volatile boolean redirect = true;

public StreamRedirector(OutputStream out, InputStream in) {      
    this.out = out;
    this.in = in;
    
    Thread t = new Thread(new RedirectorRun(), "Stream Redirector");
    t.setDaemon(true);
    t.start();        
}

public void stopRedirect() {
    redirect = false;
}

private class RedirectorRun implements Runnable {
    public void run() {
        try {
            int nextByte = in.read();
            while (nextByte != -1 && redirect) {
                out.write(nextByte);
                nextByte = in.read();
            }
        } catch (IOException e) {}
    }
}    

}[/code]

Para redirecionar a saída do processo para o outputStream padrão, basta fazer, antes do waitFor:

StreamRedirector redirector = new StreamRedirector(System.out, process.getInputStream());            

E após o waitFor, não se esqueça de fazer:

redirector.stopRedirect();

O que eu reparei eh que essa sugestao funciona = a eu colocar somente:

new PrintStream(process.getInputStream()).start();
process.waitFor();

Com isso ele imprime no console tb… e nao trava

No Caso… nao tem como eu redirecionar a saida para uma TextArea do Swing?
Quero q ele plote a saida na tela pra mim… e nao no console :smiley:

Obrigada

Tem sim, é só criar um OutputStream que escreve num JTextArea…

[code]public class TextAreaOutputStream extends OutputStream {
private JTextArea txtArea;
public TextAreaOutputStream(JTextArea txtArea) {
if (txtArea == null)
throw new IllegalArgumentException(“Text area cannot be null!”);

    this.txtArea = txtArea;
}

@Override public void write(int b) throws IOException {        
    byte[] ch = new byte[] {(byte)b};
    txtArea.append(new String(ch));
}

@Override public void write(byte[] b, int off, int len) throws IOException {
    String text = new String(b, off, len);
    txtArea.append(text);
}

}[/code]

E depois no seu código, você faz:

StreamRedirector redirector = new StreamRedirector(new TextAreaOutputStream(seuTextArea), process.getInputStream());

Como você dá start num PrintStream()? É algum PrintStream personalizado de vocês? Por que eu não consigo fazer disso por aqui não…

Na verdade, você continua lendo linha a linha, mas ao invés de jogar para o TextArea direto, jogue para um StringBuilder. Só ao final, faça setTextArea.setText(stringBuilder.toString());

[quote=ViniGodoy][quote=ana_tf]
new PrintStream(process.getInputStream()).start();
[/quote]

Como você dá start num PrintStream()? É algum PrintStream personalizado de vocês? Por que eu não consigo fazer disso por aqui não…[/quote]

Bom… nao sei c eh pq estou no WINDOWS :smiley:
mas funcionou :smiley:
Vi nesse site:

http://support.microsoft.com/kb/326709/pt-br

[quote=ViniGodoy]Tem sim, é só criar um OutputStream que escreve num JTextArea…

[code]public class TextAreaOutputStream extends OutputStream {
private JTextArea txtArea;
public TextAreaOutputStream(JTextArea txtArea) {
if (txtArea == null)
throw new IllegalArgumentException(“Text area cannot be null!”);

    this.txtArea = txtArea;
}

@Override public void write(int b) throws IOException {        
    byte[] ch = new byte[] {(byte)b};
    txtArea.append(new String(ch));
}

@Override public void write(byte[] b, int off, int len) throws IOException {
    String text = new String(b, off, len);
    txtArea.append(text);
}

}[/code]

E depois no seu código, você faz:

StreamRedirector redirector = new StreamRedirector(new TextAreaOutputStream(seuTextArea), process.getInputStream());

Funcionou com esse metodo… no linux funciona o waitFor() entao eu fazia assim:

 BufferedInputStream bis = new BufferedInputStream(process.getInputStream());
                 
                 int entrada = bis.read();
                 StringBuffer texto = new StringBuffer();
                 while (entrada != -1) 
                 {
                     texto.append((char) entrada);
                     
                     entrada = bis.read();
                    
                 }
                 String saida =texto.toString();

Dai eu jogava na String saida a saida da execucao :frowning: … e no windows nada de funcionar… estranhu ne ? :smiley:

Windows eh uma nhaca msm …

É só uma decisão de projeto.

O Windows deixa que os processos gerenciem os buffers de saída. Por isso ele não pode eliminar o subprocesso invocado até que esse buffer tenha sido completamente lido ou que o processo que originou o subprocesso seja fechado.

Normalmente o SO gerencia automaticamente isso com os pipes, mas no seu caso, você pegou o controle do pipe para si.

Se isso é bom ou ruim? Bom, já não entendo tanto de SO assim para saber se essa decisão é mais ou menos acertada…

Mas, em ambos os casos, o waitFor funciona. O objetivo dele é esperar que o processo seja morto. Só que a decisão de quando isso ocorre é deixada para o SO (mais uma das coisas não tão multi-plataforma assim do Java). Em todo caso, acho que a solução da thread separada não só é mais interativa, como funciona em todos os sistemas operacionais que eu já testei (Windows, Linux, Mac).

Vc viu a Classe PrintStream né?

[code]
class PrintStream extends Thread
{
java.io.InputStream __is = null;
public PrintStream(java.io.InputStream is)
{
__is = is;
}

public void run() 
{
	try 
	{
		while(this != null) 
		{
			int _ch = __is.read();
			if(_ch != -1) 
				System.out.print((char)_ch); 
			else break;
		}
	} 
	catch (Exception e) 
	{
		e.printStackTrace();
	} 
}

}[/code]

Estou tentando implementar a saida nao ser na tela…

Uma duvida: quando a saida vai para o console… e eu faco um .jar da minha aplicacao… onde vai essa saida? nao tem problema?

obrigada :wink:

Você diz a saída padrão do aplicativo ou do subprocesso que você disparou?

Se for a do aplicativo, basta redirecionar a saída padrão com System.setOut. O mesmo vale para a saída da erro, com System.setErr.

Aí você pode envia-la para um arquivo ou para um textarea, o que for mais conveniente para você.

Entao… no meu console gera a saida do programa…

Quero saber se tem algum problema deixar gerando ou eh bom redirecionar para algum lugaR?

Obrigada
:slight_smile:

Se a saída é importante, tem problema sim.

Caso o usuário use o javaw, a saída do console não será exibida.

Olá

Certo, nem sempre há um console.

[]s
Luca