Problema com java.util.Scanner(InputStream).next();

5 respostas
S

Bom dia, será que alguém poderia me dar um help?
Estou com o seguinte problema, eu preciso ler a saída de um processo no Linux, porém quando esse processo for um programa que aguarda ser fechado pelo o usuário ele não deve ler nada.
O que eu estava tentando fazer no código abaixo, só que sem sucesso, no switch-case era testar se há bytes coletados na saída do processo, se não houvesse ele deveria entrar no case 0, sendo que dessa forma que pensei o código não ficaria travado no sc.next().split("\n") até o usuário fechar o programa. Na verdade o problema que eu estou tentando resolver é uma forma de eu não ficar trava no sc.next().split("\n") quando o processo executado fosse, por exemplo, o “Eclipse”. O mais interessante é que quando eu depuro este código ele tem o comportamento que desejo, porém quando executo normalmente ele sempre cai no case 0.

import java.io.*;
import java.util.Scanner;

public class Main {
	public static void main(String... args) {
		String cmd = "android";

		ProcessBuilder pb = new ProcessBuilder("bash", "-c", cmd);
		pb.redirectErrorStream(true);
		try {
			Process p = pb.start();
			InputStream input = p.getInputStream();
			int inputaAvaiable = input.available();
			switch(inputaAvaiable) {
				case 0:
					System.out.println("Executado: "+ cmd);
					break;
				default:
					Scanner sc = new Scanner(input);
					// Captura a quebra de linha
					sc.useDelimiter("\r");
					String[] saida = sc.next().split("\n");
					for(String s: saida)
						System.out.print(s +"\n");
					break;
			}
			input.close();
		} catch (Exception e) {
			System.out.println("Problema com a classe comandos");
			e.printStackTrace();
		}
	}
}

5 Respostas

V

Quando você depura, o código roda devagar, e dá tempo de ter saída no input.

Normalmente faz-se a leitura de streams de processos através de uma thread separada, que roda um while. Assim seu while trava apenas no waitFor(), no ponto onde você quer esperar pela finalização do processo.
Um exemplo de thread desses está aqui: http://www.guj.com.br/java/213361-processbuilder#1087285

S

Ok, vou dar uma analisado nisso. Eu sou um novato, vou ver como aplico no meu problema. Obrigado

S

Oi Vini Godoy continuo com o mesmo problema. Baseado no seu código eu fiz assim e ele continua caindo no case 0.

import java.io.*;
import java.util.Scanner;

public class Main {
	public static void main(String... args) {
		String cmd = "ls /";
		ProcessBuilder pb = new ProcessBuilder("bash", "-c", cmd);
		pb.redirectErrorStream(true);
		try {
			Process p = pb.start();		
			InputStream input = p.getInputStream();

			ExecutaLeitura el = new ExecutaLeitura(input);

			int saidaDaLeitura = el.getRetornoExecutLeitura();
			switch(saidaDaLeitura) {
				case 0:
					System.out.println("Executado: "+ cmd);
					break;
				default:
					Scanner sc = new Scanner(input);
					// Captura a quebra de linha
					sc.useDelimiter("\r");
					String[] saida = sc.next().split("\n");
					for(String s: saida)
						System.out.print(s +"\n");
					break;
			}
			
			input.close();
		} catch (Exception e) {
			System.out.println("Problema com a classe comandos");
			e.printStackTrace();
		}
	}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;

public class ExecutaLeitura implements Runnable {
	InputStream in;
	Writer out;
	int bytesLido;
	
	ExecutaLeitura(InputStream in) {
		this.in = in;
	}
	@Override
	public void run() {
        try {  
            int nextByte = in.read();  
            while (nextByte != -1) {  
                out.write(nextByte);  
                nextByte = in.read();
            }
            setRetornoExecutLeitura(nextByte);
        } catch (IOException e) {  
            e.printStackTrace();  
        } 		
	}
	private void setRetornoExecutLeitura(int byteLido) {
		this.bytesLido = byteLido;
	}
	public int getRetornoExecutLeitura() {
		return bytesLido;
	}
}

Vou almoçar e mais tarde volto para ler sua resposta. Obrigado.

V

Ok. Agora retire o next() e o split(), pois quem cuida disso é a thread separada.

E adicione na linha 16 o comando p.waitFor(). O waitFor() também retorna o código de saída do processo.
Isso fará com que o Java aguarde o processo terminar, sem travar a leitura.

Esse saida leitura não tem o menor sentido nesse momento. Como são duas threads processando, você poderá obter ali um valor antes da leitura sequer ser feita no stream.

Pare de imaginar que as coisas são sequenciais, pois elas não são. Se você tem 2 processos, você terá duas coisas ocorrendo simultaneamente. O mesmo vale para as duas threads.
Então, ler no milisegundo seguinte não fará com que seu processo aguarde o outro processar e retornar algum valor.

S

Oi Viny me desculpe, mas não compreendi. Como faço para entrar no case 0 quando for um programa que aguarda ser fechado pelo usuário e no default quando é um programa que fecha sozinho após completar seu ciclo de vida.

Criado 9 de setembro de 2011
Ultima resposta 9 de set. de 2011
Respostas 5
Participantes 2