有没有人玩过NIO管道来过滤/拦截System.out?

正如这里建议的那样,我想在选择器循环中做到这一点。 我真正想要的是在我的选择器循环中读取写入系统的内容。

编辑1:我编写了一个完整的解决方案,只是为了找出你不能使用System.setOut重定向GC日志。 它只是直接到FD或其他东西。 显示塞子! 除非我重定向到文件并将此文件传输到我的选择器。 很多工作! 看到这里 。

一种方法如下:

  • 创建OutputStream的子类,将其输出重定向到Pipe的接收器通道
  • 使用此类重定向System.out: System.setOut(new PrintStream(new MyOutputStream(pipe));
  • 使用选择器注册管道的源通道,并获取在选择器循环中写入System.out的任何内容,即源通道的correpsonding SelectionKey被选为可读()

下面的实现是一个天真但有效的实现,它只是重定向到System.err写入System.out的所有内容:

 import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.Iterator; public class SystemOutPipe extends Thread { public static void main(String[] args) { try { SystemOutPipe sop = new SystemOutPipe(); sop.start(); System.out.println("This message should be redirected to System.err\nNow waiting 5 seconds ..."); Thread.sleep(5000L); sop.setStopped(true); sop.join(); } catch (Exception e) { e.printStackTrace(); } } private Selector selector; private Pipe pipe; private boolean stopped = false; public SystemOutPipe() throws IOException { super("SystemOutPipe"); pipe = Pipe.open(); System.setOut(new PrintStream(new PipeOutputStream(pipe))); selector = Selector.open(); pipe.source().configureBlocking(false); pipe.source().register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024)); } @Override public void run() { try { while (!isStopped()) { int n = selector.select(1L); if (n > 0) { Iterator it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = it.next(); it.remove(); if (key.isReadable()) { new ReadHandler(key).run(); } } } } } catch (Exception e) { e.printStackTrace(); // writes to System.err ! } } public synchronized boolean isStopped() { return stopped; } public synchronized void setStopped(final boolean stopped) { this.stopped = stopped; } public class ReadHandler implements Runnable { private final SelectionKey key; public ReadHandler(final SelectionKey key) { this.key = key; } @Override public void run() { ByteBuffer bbuf = (ByteBuffer) key.attachment(); ReadableByteChannel channel = (ReadableByteChannel) key.channel(); try { int count = 0; do { bbuf.clear(); count = channel.read(bbuf); if (count > 0) System.err.write(bbuf.array(), 0, count); } while(count > 0); } catch (IOException e) { e.printStackTrace(); key.cancel(); } } } public class PipeOutputStream extends OutputStream { private final Pipe pipe; public PipeOutputStream(final Pipe pipe) { this.pipe = pipe; } @Override public void write(final int b) throws IOException { write(new byte[] { (byte) b }); } @Override public void write(final byte[] b) throws IOException { write(b, 0, b.length); } @Override public void write(final byte[] b, final int off, final int len) throws IOException { ByteBuffer bbuf = ByteBuffer.wrap(b, off, len); bbuf.position(len); bbuf.flip(); int count = 0; while (count < len) { int n = pipe.sink().write(bbuf); if (n == 0) { // let's wait a bit and not consume cpu try { Thread.sleep(1L); } catch (InterruptedException e) { throw new IOException(e); } } else count += n; } } } }