zoukankan      html  css  js  c++  java
  • 【java I/O流总结】PrintWriter总结

    PrintWriter是字符输出流一个重要的方法,其源码非常简单易懂。下面基于源码来分析PrintWriter跟之前的BufferWriter、FileWriter之间的区别。

    构造函数

    public PrintWriter(Writer out,
                       boolean autoFlush) {
        super(out);
        this.out = out;
        this.autoFlush = autoFlush;
        lineSeparator = java.security.AccessController.doPrivileged(
            new sun.security.action.GetPropertyAction("line.separator"));
    }
    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可以用来包装Writer的任意子类,当包装OutputStream时,默认包装一层BufferWriter。当然也可以将File或者File路径作为参数,实质上一样,如下所示:

    public PrintWriter(String fileName) throws FileNotFoundException {
        this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
             false);
    }
    
    /* Private constructor */
    private PrintWriter(Charset charset, File file)
        throws FileNotFoundException
    {
        this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)),
             false);
    }
    

    构造函数里的autoFlush参数默认是false,当设置true时开启自动刷新,当运行println()/printf()/format()方法时,会自动刷新缓冲区。

    输出方法

    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;
        }
    }
    

    如果包装了BufferWriter,则out.write(s, off, len)这一行直接转至BufferWriter的对应方法。其它char、char[]格式参数的重载方法大同小异。

    输出格式化

    PrintWriter中增添了许多数据格式化的代码,即兼容不同类型的变量,float、int等等,如下所示:

    public void print(Object obj) {
        write(String.valueOf(obj));
    }
    public void print(double d) {
        write(String.valueOf(d));
    }
    

    实际上都是使用String.valueOf()将其转化成String,实现不同类型数据的兼容。除此之外,还对每种类型变量实现了println()功能,即换行,如下:

    public void println() {
        newLine();
    }
    public void println(long x) {
        synchronized (lock) {
            print(x);
            println();
        }
    }
    
    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;
        }
    }
    

    newLine()输出换行,同时执行out.flush()刷新缓冲区。

    PrintWriter还提供了printf方法,支持指定格式的输出,实则调用的是format方法,如下:

    //Locale l表示语言地区
    public PrintWriter printf(Locale l, String format, Object ... args) {
        return format(l, format, 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;
    }
    

    同样,执行format的过程中也会造成缓冲区刷新(若autoFlush为true)。

    注意:若PrintWriter没有包装BufferWriter 譬如直接包装FileWriter,这样缓冲区直接调用StreamEncoder中的flush刷新字节缓冲区;若用了BufferWriter,则调起BufferWriter中的flush函数,先刷新字符缓冲区,再同样刷新StreamEncoder中的字节缓冲区。

    异常处理

    PrintWriter不会抛出异常,也不需要在外部处理异常,观察前面的write函数可知,方法内部已经做了try catch操作,同时维护了一个trouble布尔变量,可利用它告知外部是否有异常。例如checkError()方法。同时与之相对应的,有setError()和clearError()方法。

    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();
        }
        return trouble;
    }
    
    protected void setError() {
        trouble = true;
    }
    
    protected void clearError() {
        trouble = false;
    }
    

    append与write区别

    PrintWriter中有两个append方法,如下:

    public PrintWriter append(CharSequence csq) {
        if (csq == null)
            write("null");
        else
            write(csq.toString());
        return this;
    }
    
    public PrintWriter append(CharSequence csq, int start, int end) {
        CharSequence cs = (csq == null ? "null" : csq);
        write(cs.subSequence(start, end).toString());
        return this;
    }
    

    感觉这个append没什么用,跟write的区别在于,参数可以传入null,还有参数是CharSequence类型字符序列(String,StringBuilder,StringBuffer都实现了这个接口)。

    PrintWriter特点总结

    • 可以兼容多种变量类型的输出,可用printf自定义输出格式,也可用println换行输出;
    • 设置autoflush为true时,可在换行或者format时自动刷新缓冲区;
    • 不会抛出异常。
  • 相关阅读:
    more命令
    mktemp命令
    有效的括号字符串
    mc命令
    字符串相加
    Vue中虚拟DOM的理解
    chattr命令
    记近一年线上项目经验及架构变更记录
    微博AnalysisQl动态数据视图元数据设计
    搭建prometheus+grafana监控SpringBoot应用入门
  • 原文地址:https://www.cnblogs.com/buptleida/p/12593483.html
Copyright © 2011-2022 走看看