Home / Programmazione / Java / Catturare l'output di un comando in Java
Mattepuffo

Catturare l'output di un comando in Java

Catturare l'output di un comando in Java

Quando lanciamo un comando da un nostro programma in Java (Swing), di default non ne vediamo l'output.

E il motivo è che, generalmente, viene mandato sullo standard output, che non è la interfaccia scritta in Java.

In molti casi, però, potrebbe essere importante catturare l'output, soprattutto per vedere a che punto siamo con la sua esecuzione.

Oggi vediamo proprio questo: come visualizzare l'output di un comando su una JTextArea.

Il programma che lanceremo sarà youtube-dl, programma da riga di comando per scaricare la musica in formato MP3 da Youtube.

Nel nostro JFrame dovremmo avere almeno questi componenti:

  • JTextField per immetere il link al video
  • JTextArea per vedere l'output
  • JButton per avviare il comando

Nel JFrame leghiamo un evento al JButton:

private Process p;
private StartYDL ydl;

btnStart.addActionListener((ActionEvent e) -> {
    start();
});
........................................................................
    private void start() {
        ydl = new StartYDL(txtOutput, txtLink, btnStart);
        if (StringUtils.isNotBlank(txtLink.getText())) {
            try {
                String cmd = "youtube-dl -x --audio-format mp3 -o " " + txtLink.getText();
                p = Runtime.getRuntime().exec(cmd);
                ydl.commence(p);
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(this, ex.getMessage());
            }
        } else {
            JOptionPane.showMessageDialog(this, "Inserire un link");
        }
    }

Qui facciamo un pò di controlli e poi lanciamo il comando con Runtime.

A questo punto vediamo la classe StartYDL:

public class StartYDL implements Runnable {

    protected final JTextArea textArea;
    protected final JTextField txtLink;
    protected final JButton btn;
    protected Reader reader = null;
    private Thread thread;

    public StartYDL(JTextArea textArea, JTextField txtLink, JButton btn) {
        this.textArea = textArea;
        this.txtLink = txtLink;
        this.btn = btn;
    }

    public void commence(Process p) {
        InputStream in = p.getInputStream();
        reader = new InputStreamReader(in);
        thread = new Thread(this);
        thread.start();
    }

    @Override
    public void run() {
        StringBuilder sb = new StringBuilder();
        btn.setEnabled(false);
        txtLink.setEnabled(false);
        try {
            while (reader != null) {
                int c = reader.read();
                if (c == -1) {
                    return;
                }
                sb.append((char) c);
                setText(sb.toString());
            }
        } catch (IOException ex) {
            sb.append("nnERROR:n").append(ex.toString());
            setText(sb.toString());
        } finally {
            try {
                reader.close();
                setText("");
                setText("DOWNLOAD COMPLETATO");
                setTextLink("");
            } catch (IOException ex) {
                sb.append(ex.getMessage());
            }
        }
    }

    public void stop() {
        thread.interrupt();
        setText("DOWNLOAD CANCELLATO");
        setTextLink("");
    }

    private void setText(final String text) {
        EventQueue.invokeLater(() -> {
            textArea.setText(text);
        });
    }

    private void setTextLink(final String text) {
        EventQueue.invokeLater(() -> {
            txtLink.setText(text);
            btn.setEnabled(true);
            txtLink.setEnabled(true);
            txtLink.requestFocus();
        });
    }
}

Questa classe implementa Runnable, e lancia il programma in un altro Thread.

Al costruttore gli passiamo la JTextArea, la JTextField e il JButton, sui quali eseguiamo delle "operazioni" durante l'esecuzione del programma in background.

Ovviamente, questo esempio non è dei più basici, ma fa capire varie cose che possono essere importanti!

Potete usare il comando che volete, e anche i componenti grafici che vi servono.

Basterà modificare il comando lanciato con Runtime, e i parametri dati al csotruttore di StartYDL.

Infine, ci sono sicuramente modi migliori da un punto di vista "stilistico", però questo metodo è abbastanza veloce da mettere su; e non è sbagliato.

Enjoy!