• 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()函数进行打印。而打印呢,也是一层一层向上调用,回到最开始的输出流。一下一上。

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

  • 相关阅读:
    判断微信浏览器
    文章迁移
    ECharts使用—折线图动态加载
    vue-cli入门
    gulp使用详解
    gulp使用入门
    Chrome扩展插件流程
    div界面元素生成图片
    xss攻击与防御
    bootstrap-table使用详解
  • 原文地址:https://www.cnblogs.com/lippon/p/14123861.html
Copyright © 2020-2023  润新知