標準出力された内容を貰ってくる遊び
プログラムで標準出力(System.out)に対して書き込んだ内容を取得するための方法。
例外安全性とかは考慮していないけれど、おもちゃとしては十分。
System.setOutでPrintStreamを継承したデリゲータを登録する。
ここで、このStreamのwriteメソッドに書かれた内容を、登録したWriterにも書き出すように設定する。(2つのwriteメソッドのオーバーライド)
これで、Writerに書かれた内容はPipedReaderを経由して取得できるようになる。
LineGetterは(標準出力された時にWriter => Readerを経由して)出力された文字列を取得する。この際取得した文字列は、後で使える用にlinesに保持しておく。
外部から文字列群が取得されたら、linesの内容は消去する。
この方法により、コレまでに標準出力された文字列を取得できる。
ただし、別Threadによる取得なので、何時その文字列が生成されるかは確定では無い。
なので、ここではLineGetterが生きている間監視し、文字列の取得を行って見た。
なお、ただの標準出力をしたい場合は、初期設定のSystem.outを取ってあるので、それを用いている。
サブプロセス関連で遊んでいたら出来ていたので記す。
ただし、安全かどうかは自分も知らない。(重要な事なので2回言いました)
以下、ソースコード&出力例。
// ソースコード import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PipedReader; import java.io.PipedWriter; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class SystemOutTest { private final static PrintStream out = System.out; public static void main(String[] args) throws Exception { PipedWriter pWriter = new PipedWriter(); final BufferedReader reader = new BufferedReader(new PipedReader(pWriter)); class LineGetter extends Thread { private final List<String> lines = new ArrayList<String>(); public void run() { while(true) { try { String line = reader.readLine(); if( line == null ) break; synchronized (lines) { lines.add(line); SystemOutTest.out.println("add: "+ line); } } catch (IOException e) { e.printStackTrace(); } } }; public List<String> newlines() { synchronized (lines) { List<String> res = new ArrayList<String>(lines); lines.clear(); return res; } } } final LineGetter getter = new LineGetter(); getter.start(); new Thread() { public void run() { while(getter.isAlive()) { for(String str : getter.newlines()) { SystemOutTest.out.println("[get]: " + str); } } } }.start(); PrintWriterDelegator delegate = new PrintWriterDelegator(pWriter); System.setOut(delegate); Scanner stdin = new Scanner(System.in); while(true) { String line = stdin.nextLine(); System.out.println(line); } } } class PrintWriterDelegator extends PrintStream { private final PipedWriter writer; public PrintWriterDelegator(PipedWriter writer) { super(System.out); this.writer = writer; } @Override public void write(byte[] buf, int off, int len) { super.write(buf, off, len); ByteArrayOutputStream stream = new ByteArrayOutputStream(); stream.write(buf, off, len); try { writer.write(stream.toString()); writer.flush(); } catch (IOException e) { e.printStackTrace(); } } @Override public void write(int b) { super.write(b); try { writer.write(b); writer.flush(); } catch (IOException e) { e.printStackTrace(); } } }
// 出力
num
num
add: num
[get]: num
piyo
piyo
add: piyo
[get]: piyo
hoge
hoge
add: hoge
[get]: hoge
exit
exit
add: exit
[get]: exit