About

本サイトについて

趣味で開発したプログラムや開発メモを載せています。
ソースコードはGithubで公開しつつ、なるべく後から分かるように解説に努めてますので、
誰かのお役に立てれば嬉しいです。

プロフィール

kght6123

佐賀県出身で1985年生まれ。
三重県四日市市在住のシステムエンジニア。家庭を大事にしたい2児の父。

kght6123.page

外部プロセスを実行して、標準出力とエラーの両方を取得できるようにした

2022-10-01T11:54:24.868Z

解説

外部プロセスを実行して、標準出力とエラーの両方を取得できるようにしました。

通常は、非同期で標準出力とエラーを取得する必要があり、毎回、非同期処理を書くのが面倒なため

その処理をInputStreamThreadクラスとProcessTaskを作ることで

どのような、外部プロセスの実行でも使いまわせるようにしました。

ソースコード

private static String execute(final ProcessTask task) {
    
    final StringBuilder output = new StringBuilder();
    final ExecutorService pool = Executors.newSingleThreadExecutor();
    try
    {
        final Future<Integer> future = pool.submit(task);
        final int exitValue = future.get(60, TimeUnit.SECONDS); // 60秒でタイムアウト
        
        System.out.println("command = " + task.toString() + ";return code = " + exitValue + ".");
        
        //標準出力の内容を出力
        for (final String s : task.getInputStream().getStringList()) {
            output.append(s).append("\r\n");
        }
        //標準エラーの内容を出力
        for (final String s : task.getErrorStream().getStringList()) {
            System.err.println(s);
        }
        return output.toString();
    }
    catch (InterruptedException | ExecutionException | TimeoutException e)
    {
        throw new BuildException(e);
    }
    finally
    {
        pool.shutdownNow();
    }
}
import java.util.concurrent.Callable;

public class ProcessTask implements Callable<Integer> {
    
    private final String[] commands;
    private InputStreamThread inputStream;
    private InputStreamThread errorStream;
    
    public ProcessTask(String... commands)
    {
        super();
        this.commands = commands;
    }
    
    @Override
    public Integer call() throws Exception
    {
        final ProcessBuilder pb = new ProcessBuilder(commands);
        final Process process = pb.start();
        
        try
        {
            //InputStreamのスレッド開始
            this.inputStream = new InputStreamThread(process.getInputStream());
            this.errorStream = new InputStreamThread(process.getErrorStream());
            
            this.inputStream.start();
            this.errorStream.start();
            
            process.waitFor();
            
            // InputStreamのスレッド終了待ち
            this.inputStream.join();
            this.errorStream.join();
            
            return process.exitValue();
        }
        catch (final Exception e)
        {
            System.out.println(e.getClass() + "\t" + e.getMessage());
            process.destroy();
            throw e;
        }
    }
    
    public InputStreamThread getInputStream() {
        return inputStream;
    }
    public InputStreamThread getErrorStream() {
        return errorStream;
    }

    @Override public String toString() {
        final StringBuilder sb = new StringBuilder();
        
        for (final String command : commands) {
            sb.append(command);
            sb.append(",");
        }
        return sb.toString();
    }
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

public class InputStreamThread extends Thread {
    private BufferedReader br;
    
    private List<String> list = new ArrayList<String>();
    
    /** コンストラクター */
    public InputStreamThread(InputStream is) {
        br = new BufferedReader(new InputStreamReader(is));
    }
    
    /** コンストラクター */
    public InputStreamThread(InputStream is, String charset) {
        try {
            br = new BufferedReader(new InputStreamReader(is, charset));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
    
    @Override
    public void run() {
        try {
            for (;;) {
                String line = br.readLine();
                if (line == null)   break;
                list.add(line);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    /** 文字列取得 */
    public List<String> getStringList() {
        return list;
    }
}
関連タグ