PrintStream类的学习与多目的地输出重定向问题

来源:互联网 发布:淘宝卓辰数码是真是假 编辑:程序博客网 时间:2024/05/05 23:27

最近开发的Dodo工具箱中需要一个日志功能,当然现在已经有很成熟很好用的Log4j,但是我觉得作为一个菜鸟,有必要自己开发一个简单的日志处理模块。下面简介该模块的设计与输出重定向这个难点。

用例设计:


类设计:


实现难点——输出重定向:

        我是这样设想的,日志来源于三个方面 1其他模块使用Logger记录的日志信息 2 系统执行过程中需要输出的信息 3 系统在运行过程中碰到的错误信息。日志输出的目的也有三个地方,第一:控制台 第二:日志文件 第三:gui即时信息窗口。

        如果只是单目的地的重定向十分简单,比如说想把System.err的信息重定向到文件out,只需在系统启动时调用如下两行即可:

PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream("out")));System.setErr(out);
           

        现在的难点在于需要将错误信息输出到多个目的地(文件,控制台,gui窗口),没有一个适合的PrintStream的子类来完成这个任务,那么我们就需要继承PrintStream,并在这个子类中重新print方法来完成我们的输出逻辑,我定义的该类的名称为IORedirect,该类的源码如下:

package toolBox.core.utility;import java.io.FileNotFoundException;import java.io.PrintStream;import java.util.Date;import java.util.Vector;import com.ibm.icu.text.SimpleDateFormat;/** * The class pipelines print/println's to several PrintStream. Useful for * directing system.out and system.err to external files etc. *  * @author jiangkai *  */public class IORedirect extends PrintStream {protected static SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");/**The default target output stream*/protected PrintStream default_target=null;/**The different target output streams*/protected Vector<PrintStream> targets=null;/** */protected Vector<Boolean> appendHeader = null;/** */protected String prefix = null;/** * initializes the object, with a default printstream. */public IORedirect(PrintStream s) {this(s,"defaultoutput");}public IORedirect(PrintStream s,String p){super(s);default_target = s;prefix = p;targets = new Vector<PrintStream>();appendHeader = new Vector<Boolean>();clear();}/** * removes all streams and places the default printstream, if any, again in * the list. *  * @see #getDefault() */public void clear() {targets.clear();appendHeader.clear();if (getDefault() != null){targets.add(getDefault());appendHeader.add(true);}}/** * returns the default printstrean, can be NULL. *  * @return the default printstream * @see #m_Default */public PrintStream getDefault() {return default_target;}public void defaultPrint(String x){if(default_target!=null)default_target.print(x);}public void defaultPrintln(String x){if(default_target!=null)default_target.println(x);}/** * adds the given PrintStream to the list of streams, with NO timestamp and * NO prefix. *  * @param p *            the printstream to add */public void addPrintStream(PrintStream p) {addPrintStream(p,false);}public void addPrintStream(PrintStream p,boolean ah){if (!targets.contains(p)){targets.add(p);appendHeader.add(ah);}}public void removePrintStream(PrintStream p) {if (targets.contains(p)){int index = targets.indexOf(p);targets.remove(index);appendHeader.remove(index);}}public boolean containsPrintStream(PrintStream p) {return targets.contains(p);}public int size() {return targets.size();}public void flush() {for (PrintStream element : targets)element.flush();}protected void printHeader(){for(PrintStream element:targets)if(appendHeader.get(targets.indexOf(element)))element.print(dateformat.format(new Date())+" "+prefix+"\n\t");}@Overridepublic void print(int x) {printHeader();for (PrintStream element : targets)element.print(x);flush();}@Overridepublic void print(long x) {printHeader();for (PrintStream element : targets)element.print(x);flush();}@Overridepublic void print(float x) {printHeader();for (PrintStream element : targets)element.print(x);flush();}@Overridepublic void print(double x) {printHeader();for (PrintStream element : targets)element.print(x);flush();}@Overridepublic void print(boolean x) {printHeader();for (PrintStream element : targets)element.print(x);flush();}@Overridepublic void print(char x) {printHeader();for (PrintStream element : targets)element.print(x);flush();}@Overridepublic void print(char[] x) {printHeader();for (PrintStream element : targets)element.print(x);flush();}@Overridepublic void print(String x) {printHeader();for (PrintStream element : targets)element.print(x);flush();}@Overridepublic void print(Object x) {printHeader();for (PrintStream element : targets)element.print(x);flush();}@Overridepublic void println(int x) {printHeader();for (PrintStream element : targets)element.println(x);flush();}@Overridepublic void println(long x) {printHeader();for (PrintStream element : targets)element.println(x);flush();}@Overridepublic void println(float x) {printHeader();for (PrintStream element : targets)element.println(x);flush();}@Overridepublic void println(double x) {printHeader();for (PrintStream element : targets)element.println(x);flush();}@Overridepublic void println(boolean x) {printHeader();for (PrintStream element : targets)element.println(x);flush();}@Overridepublic void println(char x) {printHeader();for (PrintStream element : targets)element.println(x);flush();}@Overridepublic void println(char[] x) {printHeader();for (PrintStream element : targets)element.println(x);flush();}@Overridepublic void println(String x) {printHeader();for (PrintStream element : targets)element.println(x);flush();}@Overridepublic void println(Object x) {printHeader();for (PrintStream element : targets)element.println(x);flush();}/** * Writes <code>len</code> bytes from the specified byte array starting at * offset <code>off</code> to this stream. If automatic flushing is enabled * then the <code>flush</code> method will be invoked. *  * <p> * Note that the bytes will be written as given; to write characters that * will be translated according to the platform's default character * encoding, use the <code>print(char)</code> or <code>println(char)</code> * methods. *  * @param buf *            A byte array * @param off *            Offset from which to start taking bytes * @param len *            Number of bytes to write */public void write(byte buf[], int off, int len) {for (PrintStream element : targets)element.write(buf, off, len);flush();}/** * Writes the specified byte to this stream. If the byte is a newline and * automatic flushing is enabled then the <code>flush</code> method will be * invoked. *  * <p> * Note that the byte is written as given; to write a character that will be * translated according to the platform's default character encoding, use * the <code>print(char)</code> or <code>println(char)</code> methods. *  * @param b *            The byte to be written * @see #print(char) * @see #println(char) */public void write(int b) {for (PrintStream element : targets)element.write(b);flush();}public static void main(String[] args) throws FileNotFoundException{IORedirect stdRedirect = new IORedirect(System.err,"stderr");//stdRedirect.addPrintStream(System.err);System.setErr(stdRedirect);System.err.println("error");//stdRedirect.addPrintStream(System.out);//System.setOut(stdRedirect);//System.out.println("no");}}
              现在一目了然了,我们的输出逻辑在于重写PrintStream类中的Print函数,在该函数中我们自己定义需要向那写输出流输出日志信息,我在这里的写法是
@Overridepublic void println(boolean x) {printHeader();for (PrintStream element : targets)element.println(x);flush();}
对于targets中的每一个输出流输出信息,当然,你可以在这边直接写文件输出的逻辑,窗口输出的逻辑,但是当前这种写法使得IORedirect这个类更加通用,不管你是什么输出流,只要注册到该IORediect类即可。

          下面贴出该类的使用办法:

IORedirect stdoutRedirect = new IORedirect(System.out, "stdout");System.setOut(stdoutRedirect);stdoutRedirect.addPrintStream(m_windowStream, true);stdoutRedirect.addPrintStream(m_FileStream,true);


这样,即将m_windowStream和m_FileStream注册到了该重定向对象中,这样系统的输出会输出到m_windowStream和m_FileStream这两个输出流中去,当然了,m_windowStream和m_FileStream也必须是PrintStream的子类,关于写法很简单,这里不再啰嗦。


原创粉丝点击