java截获标准输出(2)(转)

  java截获标准输出(2)(转)[@more@]startByteArrayReaderThread()方法是整个类真正的关键所在。这个方法的目标很简单,就是创建一个定期地检查 ByteArrayOutputStream缓冲区的线程。缓冲区中找到的所有数据都被提取到一个byte数组,然后写入到 PipedOutputStream。由于PipedOutputStream对应的PipedInputStream由getInputStream ()返回,从该输入流读取数据的线程都将读取到原先发送给ByteArrayOutputStream的数据。前面提到,LoopedStreams类解决了管道流存在的前二个问题,我们来看看这是如何实现的。

ByteArrayOutputStream具有根据需要扩展其内部缓冲区的能力。由于存在“完全缓冲”,线程向getOutputStream ()返回的流写入数据时不会被阻塞。因而,第一个问题不会再给我们带来麻烦。另外还要顺便说一句,ByteArrayOutputStream的缓冲区永远不会缩减。例如,假设在能够提取数据之前,有一块500 K的数据被写入到流,缓冲区将永远保持至少500 K的容量。如果这个类有一个方法能够在数据被提取之后修正缓冲区的大小,它就会更完善。

第二个问题得以解决的原因在于,实际上任何时候只有一个线程向PipedOutputStream写入数据,这个线程就是由 startByteArrayReaderThread()创建的线程。由于这个线程完全由LoopedStreams类控制,我们不必担心它会产生 IOException异常。

LoopedStreams类还有一些细节值得提及。首先,我们可以看到byteArrayOS和pipedIS实际上分别是 ByteArrayOutputStream和PipedInputStream的派生类的实例,也即在它们的close()方法中加入了特殊的行为。如果一个LoopedStreams对象的用户关闭了输入或输出流,在startByteArrayReaderThread()中创建的线程必须关闭。覆盖后的close()方法把keepRunning标记设置成false以关闭线程。另外,请注意startByteArrayReaderThread ()中的同步块。要确保在toByteArray()调用和reset()调用之间ByteArrayOutputStream缓冲区不被写入流的线程修改,这是必不可少的。由于ByteArrayOutputStream的write()方法的所有版本都在该流上同步,我们保证了 ByteArrayOutputStream的内部缓冲区不被意外地修改。

注意LoopedStreams类并不涉及管道流的第三个问题。该类的getInputStream()方法返回 PipedInputStream。如果一个线程从该流读取,一段时间后终止,下次数据从ByteArrayOutputStream缓冲区传输到 PipedOutputStream时就会出现IOException异常。

二、捕获Java控制台输出
Listing 5的ConsoleTextArea类扩展Swing JTextArea捕获控制台输出。不要对这个类有这么多代码感到惊讶,必须指出的是,ConsoleTextArea类有超过50%的代码用来进行测试。

【Listing 5:截获Java控制台输出】
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.text.*;

public class ConsoleTextArea extends JTextArea {
public ConsoleTextArea(InputStream[] inStreams) {
for(int i=0; 我 startConsoleReaderThread(生态基<我>);
}//ConsoleTextArea ()

公共ConsoleTextArea()抛出IOException {
最后LoopedStreams ls=new LoopedStreams ();

//重定向System . out和系统。犯错
PrintStream ps=new PrintStream (ls.getOutputStream ());
System.setOut (ps);
System.setErr (ps);

startConsoleReaderThread (ls.getInputStream ());
}//ConsoleTextArea ()


私人空startConsoleReaderThread (
InputStream生态基){
最后BufferedReader BR=
新BufferedReader(新InputStreamReader(生态基));
新线程(新Runnable () {
公共空运行(){
=new StringBuffer StringBuffer某人();
尝试{
字符串s;
文档doc=getDocument ();
, ((s=br.readLine ()) !=null) {
布尔caretAtEnd=false;
caretAtEnd=getCaretPosition ()==doc.getLength()呢?
真的:假;
sb.setLength (0);
附加(sb.append (s) .append(朴归隐者;   朴归隐者;).toString());如果(caretAtEnd)

setCaretPosition (doc.getLength ());}}


抓住(IOException e) {
JOptionPane。showMessageDialog (null,
”从BufferedReader读取错误:”+ e);
system . exit (1);}}


}) .start ();
}//startConsoleReaderThread ()


//该类剩余部分的功能是进行测试
公共静态void main (String [] args) {
JFrame f=new JFrame (“ConsoleTextArea测试”);
ConsoleTextArea ConsoleTextArea=零;

尝试{
ConsoleTextArea=new ConsoleTextArea ();}

抓住(IOException e) {。
system . errprintln (
“不能创建LoopedStreams:”+ e);
system . exit (1);}


consoleTextArea.setFont (java.awt.Font.decode(“做到”)),
f.getContentPane阀门()(新JScrollPane (consoleTextArea),
java.awt.BorderLayout.CENTER);
f。setBounds (50、50、300、300);

java截获标准输出(2)(转)