zoukankan      html  css  js  c++  java
  • Java IO源码分析(四)——PrintStream

    简介

    PrintStream继承于FilterOutputStream,而FilterOutputStream用于封装其他的输出流。
    PrintStream用于给其他的输出流封装了一层打印的功能,它内部重载了很多数据类型,这样可以方便打印不同类型的数据。
    实际的输出工作,还是调用了被封装的输出流的打印函数。

    源码分析

    
    public class PrintStream extends FilterOutputStream
        implements Appendable, Closeable
    {
        // 自动fulsh标志位,如果为真,那么每次执行print、println、write 都会调用flush函数
        private final boolean autoFlush;
        // 是否有异常产生
        private boolean trouble = false;
        // 用于格式化对象
        private Formatter formatter;
    
        // 用于实现printStream支持的字符集
        private BufferedWriter textOut;
        private OutputStreamWriter charOut;
    
    
        private static <T> T requireNonNull(T obj, String message) {
            if (obj == null)
                throw new NullPointerException(message);
            return obj;
        }
    
        // 返回字符串对应的字符集对象
        private static Charset toCharset(String csn)
            throws UnsupportedEncodingException
        {
            requireNonNull(csn, "charsetName");
            try {
                return Charset.forName(csn);
            } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
                // UnsupportedEncodingException should be thrown
                throw new UnsupportedEncodingException(csn);
            }
        }
    
        // 设置输出流对象和自动flush模式
        private PrintStream(boolean autoFlush, OutputStream out) {
            super(out);
            this.autoFlush = autoFlush;
            this.charOut = new OutputStreamWriter(this);
            this.textOut = new BufferedWriter(charOut);
        }
        // 增加了输出字符集
        private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
            super(out);
            this.autoFlush = autoFlush;
            this.charOut = new OutputStreamWriter(this, charset);
            this.textOut = new BufferedWriter(charOut);
        }
    
        // 换了参数位置
        private PrintStream(boolean autoFlush, Charset charset, OutputStream out)
            throws UnsupportedEncodingException
        {
            this(autoFlush, out, charset);
        }
    
        // 只设置了输出流对象,采用默认字符集和不自动flush
        public PrintStream(OutputStream out) {
            this(out, false);
        }
    
        public PrintStream(OutputStream out, boolean autoFlush) {
            this(autoFlush, requireNonNull(out, "Null output stream"));
        }
    	
        // 全部进行初始化构造,采用encoding的字符集
        public PrintStream(OutputStream out, boolean autoFlush, String encoding)
            throws UnsupportedEncodingException
        {
            this(autoFlush,
                 requireNonNull(out, "Null output stream"),
                 toCharset(encoding));
        }
    
        public PrintStream(String fileName) throws FileNotFoundException {
            this(false, new FileOutputStream(fileName));
        }
    
        public PrintStream(String fileName, String csn)
            throws FileNotFoundException, UnsupportedEncodingException
        {
            // ensure charset is checked before the file is opened
            this(false, toCharset(csn), new FileOutputStream(fileName));
        }
    
        public PrintStream(File file) throws FileNotFoundException {
            this(false, new FileOutputStream(file));
        }
    
        public PrintStream(File file, String csn)
            throws FileNotFoundException, UnsupportedEncodingException
        {
            // ensure charset is checked before the file is opened
            this(false, toCharset(csn), new FileOutputStream(file));
        }
    
        // 确保是否存在可用的输出流
        private void ensureOpen() throws IOException {
            if (out == null)
                throw new IOException("Stream closed");
        }
    
        // 将输出流缓冲的数据输出
        public void flush() {
            synchronized (this) {
                try {
                    ensureOpen();
                    // 调用了输出流的flush函数
                    out.flush();
                }
                catch (IOException x) {
                	// 捕获处理错误
                    trouble = true;
                }
            }
        }
    
        private boolean closing = false; /* To avoid recursive closing */
    
        // 关闭输出流
        public void close() {
            synchronized (this) {
                if (! closing) {
                    closing = true;
                    try {
                        textOut.close();
                        out.close();
                    }
                    catch (IOException x) {
                        trouble = true;
                    }
                    textOut = null;
                    charOut = null;
                    out = null;
                }
            }
        }
    
        // flush数据,再检查错误标志
        public boolean checkError() {
            if (out != null)
                flush();
            if (out instanceof java.io.PrintStream) {
                PrintStream ps = (PrintStream) out;
                return ps.checkError();
            }
            return trouble;
        }
    
        // 设置错误标志位
        protected void setError() {
            trouble = true;
        }
    
        // 清除错误标志位
        protected void clearError() {
            trouble = false;
        }
    
        // 写入一个字节到输出流当中,虽然参数是int,但是输出流中将只会取低八位
        public void write(int b) {
            try {
                synchronized (this) {
                    ensureOpen();
                    out.write(b);
                    // 如果是换行符,或者是自动flush,那么就会将输出流的数据进行输出
                    if ((b == '
    ') && autoFlush)
                        out.flush();
                }
            }
            catch (InterruptedIOException x) {
                Thread.currentThread().interrupt();
            }
            catch (IOException x) {
                trouble = true;
            }
        }
    
        // 写入字节数字组的指定范围
        public void write(byte buf[], int off, int len) {
            try {
                synchronized (this) {
                    ensureOpen();
                    out.write(buf, off, len);
                    if (autoFlush)
                        out.flush();
                }
            }
            catch (InterruptedIOException x) {
                Thread.currentThread().interrupt();
            }
            catch (IOException x) {
                trouble = true;
            }
        }
    
    	// 吸写入全部的数组
        private void write(char buf[]) {
            try {
                synchronized (this) {
                    ensureOpen();
                    textOut.write(buf);
                    textOut.flushBuffer();
                    charOut.flushBuffer();
                    if (autoFlush) {
                        for (int i = 0; i < buf.length; i++)
                            if (buf[i] == '
    ')
                                out.flush();
                    }
                }
            }
            catch (InterruptedIOException x) {
                Thread.currentThread().interrupt();
            }
            catch (IOException x) {
                trouble = true;
            }
        }
    
    	// 写入字符串
        private void write(String s) {
            try {
                synchronized (this) {
                    ensureOpen();
                    textOut.write(s);
                    textOut.flushBuffer();
                    charOut.flushBuffer();
                    if (autoFlush && (s.indexOf('
    ') >= 0))
                        out.flush();
                }
            }
            catch (InterruptedIOException x) {
                Thread.currentThread().interrupt();
            }
            catch (IOException x) {
                trouble = true;
            }
        }
    
    	// 向输出流中写入一个换行符
        private void newLine() {
            try {
                synchronized (this) {
                    ensureOpen();
                    textOut.newLine();
                    textOut.flushBuffer();
                    charOut.flushBuffer();
                    if (autoFlush)
                        out.flush();
                }
            }
            catch (InterruptedIOException x) {
                Thread.currentThread().interrupt();
            }
            catch (IOException x) {
                trouble = true;
            }
        }
    
    	// 打印布尔类型
        public void print(boolean b) {
            write(b ? "true" : "false");
        }
    
    	// 打印字符
        public void print(char c) {
            write(String.valueOf(c));
        }
    
    	// 打印整型
        public void print(int i) {
            write(String.valueOf(i));
        }
    
    	// 打印长整型
        public void print(long l) {
            write(String.valueOf(l));
        }
    
    	// 打印浮点数
        public void print(float f) {
            write(String.valueOf(f));
        }
    
    	// 打印双精度浮点
        public void print(double d) {
            write(String.valueOf(d));
        }
    
    	// 打印字符数组
        public void print(char s[]) {
            write(s);
        }
    
    	// 打印字符串
        public void print(String s) {
        	// 判断字符串是否为空
            if (s == null) {
                s = "null";
            }
            write(s);
        }
    
    	// 打印对象,实际调用了对象的toString函数
        public void print(Object obj) {
            write(String.valueOf(obj));
        }
    
    	// 打印换行
        public void println() {
            newLine();
        }
    
    	// 下面的Println就是调用了上面的print加上了换行
        public void println(boolean x) {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    
        public void println(char x) {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    
        public void println(int x) {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    
        public void println(long x) {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    
        public void println(float x) {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    
        public void println(double x) {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    
        public void println(char x[]) {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    
        public void println(String x) {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    
        public void println(Object x) {
            String s = String.valueOf(x);
            synchronized (this) {
                print(s);
                newLine();
            }
        }
    
    
    	// 将args根据默认的Locale的值,按照format格式化,再写入printStream输出流
        public PrintStream printf(String format, Object ... args) {
            return format(format, args);
        }
    	// 将args根据输入的Locale的值,按照format格式化,再写入printStream输出流
        public PrintStream printf(Locale l, String format, Object ... args) {
            return format(l, format, args);
        }
    	// 根据“默认的Locale值(区域属性)”来格式化数据
        public PrintStream format(String format, Object ... args) {
            try {
                synchronized (this) {
                    ensureOpen();
                    if ((formatter == null)
                        || (formatter.locale() != Locale.getDefault()))
                        formatter = new Formatter((Appendable) this);
                    formatter.format(Locale.getDefault(), format, args);
                }
            } catch (InterruptedIOException x) {
                Thread.currentThread().interrupt();
            } catch (IOException x) {
                trouble = true;
            }
            return this;
        }
    
      	// 根据“Locale值(区域属性)”来格式化数据
        public PrintStream format(Locale l, String format, Object ... args) {
            try {
                synchronized (this) {
                    ensureOpen();
                    if ((formatter == null)
                        || (formatter.locale() != l))
                        formatter = new Formatter(this, l);
                    formatter.format(l, format, args);
                }
            } catch (InterruptedIOException x) {
                Thread.currentThread().interrupt();
            } catch (IOException x) {
                trouble = true;
            }
            return this;
        }
    
    	// 将字符序列的全部字符添加到输出流中
        public PrintStream append(CharSequence csq) {
            if (csq == null)
                print("null");
            else
                print(csq.toString());
            return this;
        }
    
    	// 将字符序列的指定位置添加的输出流中
        public PrintStream append(CharSequence csq, int start, int end) {
            CharSequence cs = (csq == null ? "null" : csq);
            write(cs.subSequence(start, end).toString());
            return this;
        }
    
    	// 输出流中添加一个字符
        public PrintStream append(char c) {
            print(c);
            return this;
        }
    
    }
    
    

    总结

    PrintStream源码中,大多数都是给传入的输出流做了一层封装,底层还是使用的传入输出流的函数。

    做些这些封装的目的就是更好的打印我们想要的数据,比如字符串是空的,我们就应该打印出一个null,而不是什么都不答应出来。

    在我们最开始学Java的时候,System.out.println("hello world");中就是使用了PrintStream进行打印。也就是将“输出到屏幕“的输出流经过文件输出流、缓冲输出流,最后装入到这里的打印输出流,最后调用这里println()函数进行打印。而打印呢,也是一层一层向上调用,回到最开始的输出流。一下一上。

    一层层封装,每一层都实现了各自不同的职责,源码设计思想博大精深。

  • 相关阅读:
    Siege 3.0 正式版发布,压力测试工具
    Pomm 1.1.2 发布,专为 PG 设计的 ORM 框架
    Whonix 0.5.6 发布,匿名通用操作系统
    国内开源 java cms,Jspxcms 2.0 发布
    EZNamespaceExtensions.Net v2013增加对上下文菜单、缩略图、图标、属性表的支持
    GNU Guile 2.0.9 发布,Scheme 实现
    jdao 1.0.4 发布 轻量级的orm工具包
    OpenSearchServer 1.4 RC4 发布
    Percona Server for MySQL 5.5.3030.2
    Samba 4.0.5 发布
  • 原文地址:https://www.cnblogs.com/lippon/p/14123861.html
Copyright © 2011-2022 走看看