Java8 I/O源码-PrintWriter

今天来学习PrintWriter。

PrintWriter,字符类型的打印输出流,用于控制文本输出流打印对象的格式化表示形式。此类实现在PrintStream中的所有print方法。它不包含用于写入原始字节的方法。

此类中的方法不会抛出I/O异常,尽管其某些构造方法可能抛出异常。客户端可能会查询调用checkError()是否出现错误。

ps:如果不想看源码,文章末尾有对源码的总结。

源码

下面看下PrintWriter的源码。

public class PrintWriter extends Writer {

    /**
     * PrintWriter的底层字符输出流
     */
    protected Writer out;

    //是否自动刷新。
    //如果为true,每次执行print(), println(), write()函数,都会调用flush()函数。
    private final boolean autoFlush;
    //是否有异常
    //当PrintWriter有异常产生时,会被本身捕获,并设置trouble为true
    private boolean trouble = false;
    //用于格式化字符串的对象
    private Formatter formatter;
    //字节打印流
    //用于checkError方法
    private PrintStream psOut = null;

    /**
     * 行分隔符
     * 在PrintWriter被创建时line.separator属性的值。
     */
    private final String lineSeparator;

    /**
     * 返回csn(字符集名字)对应的Chaset
     * csn为null或是不支持的字符集,抛出异常
     */
    private static Charset toCharset(String csn)
        throws UnsupportedEncodingException
    {
        Objects.requireNonNull(csn, "charsetName");
        try {
            return Charset.forName(csn);
        } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
            // UnsupportedEncodingException should be thrown
            throw new UnsupportedEncodingException(csn);
        }
    }

    /**
     * 创建新的PrintWriter。
     * 指定底层输出流,默认不会自动flush,采用默认字符集
     */
    public PrintWriter (Writer out) {
        this(out, false);
    }

    /**
     * 创建新的PrintWriter。
     * 指定底层输出流,指定是否自动flush,采用默认字符集
     */
    public PrintWriter(Writer out,
                       boolean autoFlush) {
        super(out);
        this.out = out;
        this.autoFlush = autoFlush;
        //line.separator属性的值
        lineSeparator = java.security.AccessController.doPrivileged(
            new sun.security.action.GetPropertyAction("line.separator"));
    }

    /**
     * 创建新的PrintWriter。
     * 指定底层输出流,不自动flush,采用默认字符集
     */
    public PrintWriter(OutputStream out) {
        this(out, false);
    }

    /**
     * 创建新的PrintWriter。
     * 指定底层输出流,指定是否自动flush,采用默认字符集
     */
    public PrintWriter(OutputStream out, boolean autoFlush) {
        this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);

        // save print stream for error propagation
        if (out instanceof java.io.PrintStream) {
            psOut = (PrintStream) out;
        }
    }

    /**
     * 创建新的PrintWriter。
     * 指定文件名,默认不自动flush,采用默认字符集
     */
    public PrintWriter(String fileName) throws FileNotFoundException {
        this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
             false);
    }

    /**
     * 私有构造方法。创建新的PrintWriter。
     * 指定文件名,默认不自动flush,采用指定字符集
     */
    private PrintWriter(Charset charset, File file)
        throws FileNotFoundException
    {
        this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)),
             false);
    }

    /**
     * 创建新的PrintWriter。
     * 指定文件名,默认不自动flush,采用指定字符集
     */
    public PrintWriter(String fileName, String csn)
        throws FileNotFoundException, UnsupportedEncodingException
    {
        this(toCharset(csn), new File(fileName));
    }

    /**
     * 创建新的PrintWriter。
     * 指定文件名,默认不自动flush,采用默认字符集
     */
    public PrintWriter(File file) throws FileNotFoundException {
        this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
             false);
    }

    /**
     * 创建新的PrintWriter。
     * 指定文件名,默认不自动flush,采用指定字符集
     */
    public PrintWriter(File file, String csn)
        throws FileNotFoundException, UnsupportedEncodingException
    {
        this(toCharset(csn), file);
    }

    /** 确认输出流是否开启。如果底层输出流不为null,则认为输出流是开启的 */
    private void ensureOpen() throws IOException {
        if (out == null)
            throw new IOException("Stream closed");
    }

    /**
     * 刷新流
     * @see #checkError()
     */
    public void flush() {
        try {
            synchronized (lock) {
                ensureOpen();
                out.flush(); 
            }
        }
        catch (IOException x) {
            //当PrintWriter有异常产生时,会被本身捕获,并设置trouble为true
            trouble = true;
        }
    }

    /**
     * 关闭该流并释放与之关联的所有系统资源。
     * 将底层输出流置为null,就把输出流关闭了
     *
     * @see #checkError()
     */
    public void close() {
        try {
            synchronized (lock) {
                if (out == null)
                    return;
                out.close();
                out = null;
            }
        }
        catch (IOException x) {
            trouble = true;
        }
    }

    /**
     * 如果流没有关闭,则刷新流且检查其错误状态。
     */
    public boolean checkError() {
        //如果流没有关闭,则刷新流
        if (out != null) {
            flush();
        }
        //检查错误状态
        if (out instanceof java.io.PrintWriter) {
            PrintWriter pw = (PrintWriter) out;
            return pw.checkError();
        } else if (psOut != null) {
            return psOut.checkError();
        }
        //如果抛出了异常,返回true
        return trouble;
    }

    /**
     * 指示已发生错误。
     * 在调用clearError()之前,此方法将导致checkError()的后续调用返回 true。
     */
    protected void setError() {
        trouble = true;
    }

    /**
     * 清除此流的错误状态。
     */
    protected void clearError() {
        trouble = false;
    }

    /**
     * 写入单个字符。
     */
    public void write(int c) {
        try {
            synchronized (lock) {
                ensureOpen();
                //调用底层输出流写入单个字符
                out.write(c);
            }
        }
        catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        }
        catch (IOException x) {
            trouble = true;
        }
    }

    /**
     * 写入字符数组的某一部分。
     */
    public void write(char buf[], int off, int len) {
        try {
            synchronized (lock) {
                ensureOpen();
                //调用底层输出流写入字符数组的某一部分
                out.write(buf, off, len);
            }
        }
        catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        }
        catch (IOException x) {
            trouble = true;
        }
    }

    /**
     * 写入字符数组。
     * 此方法不能从Writer类继承,因为它必须取消I/O异常。
     */
    public void write(char buf[]) {
        write(buf, 0, buf.length);
    }

    /**
     * 写入字符串的某一部分。
     */
    public void write(String s, int off, int len) {
        try {
            synchronized (lock) {
                ensureOpen();
                out.write(s, off, len);
            }
        }
        catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        }
        catch (IOException x) {
            trouble = true;
        }
    }

    /**
     * 写入字符串。
     * 此方法不能从Writer类继承,因为它必须取消I/O异常。
     */
    public void write(String s) {
        write(s, 0, s.length());
    }

    //写入换行符
    private void newLine() {
        try {
            synchronized (lock) {
                ensureOpen();
                out.write(lineSeparator);
                if (autoFlush)
                    out.flush();
            }
        }
        catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        }
        catch (IOException x) {
            trouble = true;
        }
    }

    /* Methods that do not terminate lines */

    /**
     * 打印boolean值。
     * 按照平台的默认字符编码将字符串转换为字节,然后写入输出流。
     */
    public void print(boolean b) {
        write(b ? "true" : "false");
    }

    /**
     * 打印字符。
     */
    public void print(char c) {
        write(c);
    }

    /**
     * 打印整数。
     * 按照平台的默认字符编码将字符串转换为字节,然后写入输出流。
     */
    public void print(int i) {
        write(String.valueOf(i));
    }

    /**
     * 打印long。
     * 按照平台的默认字符编码将字符串转换为字节,然后写入输出流。
     */
    public void print(long l) {
        write(String.valueOf(l));
    }

    /**
     * 打印一个浮点数。
     * 按照平台的默认字符编码将字符串转换为字节,然后写入输出流。
     */
    public void print(float f) {
        write(String.valueOf(f));
    }

    /**
     * 打印double精度浮点数。
     * 按照平台的默认字符编码将字符串转换为字节,然后写入输出流。
     */
    public void print(double d) {
        write(String.valueOf(d));
    }

    /**
     * 打印字符数组。
     * 按照平台的默认字符编码将字符转换为字节,然后写入输出流。
     */
    public void print(char s[]) {
        write(s);
    }

    /**
     * 打印字符串。
     * 如果参数为null,则打印字符串"null"
     * 否则,按照平台的默认字符编码将字符串的字符转换为字节,然后写入输出流。
     */
    public void print(String s) {
        if (s == null) {
            s = "null";
        }
        write(s);
    }

    /**
     * 打印对象。
     * 按照平台的默认字符串编码将String.valueOf(Object)方法生成的字符串转换为字节,
     * 并完全以 write(int) 方法的方式写入这些字节。
     */
    public void print(Object obj) {
        write(String.valueOf(obj));
    }

    /* Methods that do terminate lines */

    /**
     * 通过写入行分隔符字符串终止当前行。
     * 行分隔符字符串由系统属性line.separator定义,不一定是单个换行符('\n')。
     */
    public void println() {
        newLine();
    }

    /**
     * 打印boolean值,然后终止该行。
     */
    public void println(boolean x) {
        synchronized (lock) {
            print(x);
            println();
        }
    }

    /**
     * 打印字符,然后终止该行。
     */
    public void println(char x) {
        synchronized (lock) {
            print(x);
            println();
        }
    }

    /**
     * 打印整数,然后终止该行。
     */
    public void println(int x) {
        synchronized (lock) {
            print(x);
            println();
        }
    }

    /**
     * 打印long整数,然后终止该行。
     */
    public void println(long x) {
        synchronized (lock) {
            print(x);
            println();
        }
    }

    /**
     * 打印浮点数,然后终止该行。
     */
    public void println(float x) {
        synchronized (lock) {
            print(x);
            println();
        }
    }

    /**
     * 打印双精度浮点数,然后终止该行。
     */
    public void println(double x) {
        synchronized (lock) {
            print(x);
            println();
        }
    }

    /**
     * 打印字符数组,然后终止该行。
     */
    public void println(char x[]) {
        synchronized (lock) {
            print(x);
            println();
        }
    }

    /**
     * 打印String,然后终止该行。
     */
    public void println(String x) {
        synchronized (lock) {
            print(x);
            println();
        }
    }

    /**
     * 打印Object,然后终止该行。
     */
    public void println(Object x) {
        String s = String.valueOf(x);
        synchronized (lock) {
            print(s);
            println();
        }
    }

    /**
     * 使用指定格式字符串和参数将一个格式化字符串写入此writer中。
     * 如果启用自动刷新,则调用此方法将刷新输出缓冲区。
     *
     * @param  format 在格式字符串的语法中描述的格式字符串。
     * 格式字符串的语法可以参考http://tool.oschina.net/uploads/apidocs/jdk-zh/java/util/Formatter.html#syntax
     *
     * @param  args
     *         格式字符串中的格式说明符引用的参数。如果参数多于格式说明符,则忽略额外的参数。参数的数量是可变的,并且可以为零。
     *
     * @since  1.5
     */
    public PrintWriter printf(String format, Object ... args) {
        return format(format, args);
    }

    /**
     * 使用指定格式字符串和参数将一个格式化字符串写入此writer中。
     * 如果启用自动刷新,则调用此方法将刷新输出缓冲区。
     *
     * @param  l
     *         格式化过程中应用的locale。如果l为null,则不应用本地化。
     *
     * @param  format
     *          在格式字符串的语法中描述的格式字符串。
     *
     * @param  args
     *         格式字符串中的格式说明符引用的参数。
     *
     * @since  1.5
     */
    public PrintWriter printf(Locale l, String format, Object ... args) {
        return format(l, format, args);
    }

    /**
     * 参考public PrintWriter printf(String format, Object... args)     
     */
    public PrintWriter format(String format, Object ... args) {
        try {
            synchronized (lock) {
                ensureOpen();
                if ((formatter == null)
                    || (formatter.locale() != Locale.getDefault()))
                    formatter = new Formatter(this);
                formatter.format(Locale.getDefault(), format, args);
                if (autoFlush)
                    out.flush();
            }
        } catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        } catch (IOException x) {
            trouble = true;
        }
        return this;
    }

    /**
     * 参考printf(Locale l, String format, Object... args)
     */
    public PrintWriter format(Locale l, String format, Object ... args) {
        try {
            synchronized (lock) {
                ensureOpen();
                if ((formatter == null) || (formatter.locale() != l))
                    formatter = new Formatter(this, l);
                formatter.format(l, format, args);
                if (autoFlush)
                    out.flush();
            }
        } catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        } catch (IOException x) {
            trouble = true;
        }
        return this;
    }

    /**
     * 将指定的字符序列添加到此writer。
     * 可能不添加整个序列,也可能添加,具体取决于字符序列csq的toString指定。
     *
     * @since  1.5
     */
    public PrintWriter append(CharSequence csq) {
        if (csq == null)
            write("null");
        else
            write(csq.toString());
        return this;
    }

    /**
     * 将指定字符序列的子序列添加到此writer。
     *
     * @since  1.5
     */
    public PrintWriter append(CharSequence csq, int start, int end) {
        CharSequence cs = (csq == null ? "null" : csq);
        write(cs.subSequence(start, end).toString());
        return this;
    }

    /**
     * 将指定字符添加到此 writer。
     *
     * @since 1.5
     */
    public PrintWriter append(char c) {
        write(c);
        return this;
    }
}

总结

  • 从构造方法中可以看到,BufferedWriter包装了底层输出流,为其提供了缓冲功能。
  • 此类中的方法不会抛出I/O异常,尽管其某些构造方法可能抛出异常。客户端可能会查询调用checkError()是否出现错误。
  • print方法可以打印boolean、char 、char[]、double 、float、int、 long、Object、String这些类型。都是按照平台的默认字符串编码将String.valueOf() 方法生成的字符串转换为字节,并完全以write(int)方法的方式向输出流中写入这些字节。
  • println(type param)方法可以打印boolean、char 、char[]、double 、float、int、 long、Object、String这些类型。都是先调用print方法打印,再调用println()方法换行。
  • printf方法和format方法的效果是相同的。因为printf方法是依赖于调用format方法实现的。
  • append方法其实是依赖于out.write方法实现的。

关于PrintWriter就讲到这里,想了解更多内容请参考

版权声明
作者:潘威威

原文地址:CSDN博客-潘威威的博客-http://blog.csdn.net/panweiwei1994/article/details/78389254

本文版权归作者所有,欢迎转载。转载时请在文章明显位置给出原文作者名字(潘威威)及原文链接。请勿将本文用于任何商业用途。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值