【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时自动刷新缓冲区;
  • 不会抛出异常。
posted @ 2020-03-29 17:13  数小钱钱的种花兔  阅读(425)  评论(0编辑  收藏  举报