Java

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

kght6123

kght6123

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

解説

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

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

その処理を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;
	}
}