[重学Java基础][Java IO流][Part.8] 打印字符输出流

[重学Java基础][JavaIO流][Part.8] 打印字符输出流

PrintWriter

概述

PrintWriter缓冲字符数组输出流,继承了所有字符输出流的超类Writer类,用于向文本对象输入字符内容
很明显是一个处理流 用于处理字符数据 代理真正的节点流输出到数据汇 是一个非常实用的输出流
系统的System.out方法就是调用了内置的PrintWriter流

官方注释

格式化打印对象到文本输出流。本类实现了所有PrintStream也包含的方法。
但本类不包含写入字节流的方法,写入字节流可以使用无编码字节流。
与PrintStream不同,只有代理println,printf,format方法时且自动刷新
是启用状态,才会起效,而不是在一个新的换行符被输出时进行自动刷新。
这些方法使用平台自己的换行符而不是普通的换行符

此类的所有方法不会跑出I/O异常,除了其中的一些构造方法。
终端可以查询是否是一些代理方法抛出的受检异常

源码分析

成员属性

代理的节点输出流
protected Writer out;
是否自动刷新 
private final boolean autoFlush;
是否有抛出异常 官方注释提到PrintWriter不抛出异常 
所以如果发生异常只是 此标志位置为false
private boolean trouble = false;
格式化参数
private Formatter formatter;
输出流 适配器模式
private PrintStream psOut = null;

成员方法

构造方法

创建一个不会自动刷新的PrintWriter 对象
 public PrintWriter (Writer out) {
        this(out, false);
    }

创建一个PrintWriter 对象,并设置是否自动刷新
如果自动刷新则 println,printf,format方法将会自动刷新输出流
public PrintWriter(Writer out,
                   boolean autoFlush) {
    super(out);
    this.out = out;
    this.autoFlush = autoFlush;
}

创建一个不会自动刷新的PrintWriter对象 
调用OutputStream作为真正的输出节点流
可以看到此方法和第一个方法的不同之处就是入参是OutputStream 
内部调用了下面的方法
public PrintWriter(OutputStream out) {
    this(out, false);
}

创建一个PrintWriter对象,并设置是否自动刷新
调用缓冲流包裹的OutputStreamWriter转换器对象输出到真正的节点流中
编码采用默认字符集
public PrintWriter(OutputStream out, boolean autoFlush) {
    this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);

    // 为了传播异常内容 保存输出流
    if (out instanceof java.io.PrintStream) {
        psOut = (PrintStream) out;
    }
}

创建一个PrintWriter对象输出数据到指定文件名的文件,并不自动刷新
内部调用缓冲流包裹的OutputStreamWriter转换器对象输出到真正的文件输出节点流中
内部调用了上面的第二个构造方法
public PrintWriter(String fileName) throws FileNotFoundException {
    this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
         false);
}

创建一个PrintWriter对象输出数据到指定文件名的文件,并不自动刷新,
根据编码名使用指定的编码方式
内部调用了下面的私有构造方法
 public PrintWriter(String fileName, String csn)
    throws FileNotFoundException, UnsupportedEncodingException
{
    this(toCharset(csn), new File(fileName));
}

私有构造方法 
内部使用缓冲流包裹的OutputStreamWriter转换器对象输出到真正的文件输出节点流中
并根据charset字符集指定编码方式
private PrintWriter(Charset charset, File file)
    throws FileNotFoundException
{
    this(new BufferedWriter(new OutputStreamWriter(
    new FileOutputStream(file), charset)),
         false);
}

创建一个PrintWriter对象输出数据到指定文件对象,并不自动刷新
 public PrintWriter(File file) throws FileNotFoundException {
    this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
         false);
}

创建一个PrintWriter对象输出数据到指定文件对象,并不自动刷新
且使用指定的编码字符集
public PrintWriter(File file, String csn)
        throws FileNotFoundException, UnsupportedEncodingException
    {
        this(toCharset(csn), file);
    }

其他

确认流是否打开
private void ensureOpen() throws IOException {
    if (out == null)
        throw new IOException("Stream closed");
}

刷新流内容方法 
内部捕捉了IOException 
所以PrintWriter不会抛出IOException 
只会改变成员属性troubled的标志位
public void flush() {
    try {
        synchronized (lock) {
            ensureOpen();
            out.flush();
        }
    }
    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();
    }
    return trouble;
}

直接设置错误标志位方法
protected void setError() {
        trouble = true;
    }
清除错误标志位方法
protected void clearError() {
    trouble = false;
}

写入数据方法 
这是一个阻塞方法 并且是线程安全的
所以捕捉了受检异常InterruptedIOException
并重新设置了线程中断以方便上级方法检测
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)
{……}

public void write(char buf[]) 
{……}

public void write(String s, int off, int len)
{……}

新一行方法 调用println换行实际上调用的就是此方法
实际上是写入了对应系统的换行符System.lineSeparator()
private void newLine() {
    try {
        synchronized (lock) {
            ensureOpen();
            out.write(System.lineSeparator());
            if (autoFlush)
                out.flush();
        }
    }
    catch (InterruptedIOException x) {
        Thread.currentThread().interrupt();
    }
    catch (IOException x) {
        trouble = true;
    }
}

打印输出方法 入参是布尔型 
然而实际上输出时是转换为了字符型了
并且采用的是默认编码
public void print(boolean b) {
    write(String.valueOf(b));
}

其他重载的打印输出方法 大同小异
我们平时调用的系统print方法就是这些方法
不是字符型的全部被转为字符型输出了
public void print(boolean b) {
    this.write(String.valueOf(b));
}

public void print(char c) {
    this.write(c);
}

public void print(int i) {
    this.write(String.valueOf(i));
}

public void print(long l) {
    this.write(String.valueOf(l));
}

public void print(float f) {
    this.write(String.valueOf(f));
}

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

public void print(char[] s) {
    this.write(s);
}

public void print(String s) {
    this.write(String.valueOf(s));
}

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

打印输出并换行方法
其实就是输出完后 追加调用了println(newline)方法
public void println(boolean x) {
    Object var2 = this.lock;
    synchronized(this.lock) {
        this.print(x);
        this.println();
    }
}
重载的都大同小异
public void println(char x) 

public void println(int x) 

public void println(long x) 

public void println(float x)

public void println(double x)

public void println(char[] x) 

字符格式化打印输出方法
入参是格式化参数format 和被格式化的字符内容 是个可变数组Object ... args
字符内容和格式化参数不必一一对应 但不能字符内容少于格式化参数
具体可以看printf的详解
此方法内部调用的是format方法
public PrintWriter printf(String format, Object ... args) {
    return format(format, args);
}

格式化打印方法 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;
}

增加了一个可指定字符区位Locale的参数 可以根据指定的区位习惯的格式进行输出
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;
}

追加打印方法 
public PrintWriter append(CharSequence csq) {
        write(String.valueOf(csq));
        return this;
    }

追加打印方法 打印字符或字符序列到输出流中
和print方法不同的是返回了本身PrintWriter 对象
可以链式调用
public PrintWriter append(CharSequence csq, int start, int end) {
    if (csq == null) csq = "null";
    return append(csq.subSequence(start, end));
}

public PrintWriter append(char c) {
    write(c);
    return this;
}

代码示例

构造一个PrintWriter 对象 并使用write方法输出 必须手动flush

    char[] chars={'爱', '吃', '拉', '面', '的','小','泉','同','学' };
    String str="爱吃拉面的小泉同学";
    File file=new File("d:\\animation.txt");
    PrintWriter pw=new PrintWriter(new FileOutputStream(file));
    pw.write(chars);
    pw.write(str);
    pw.flush();

    PrintWriter pw2=new PrintWriter("d:\\animation2.txt");
    pw2.write("王牌御史");
    pw2.flush();

运行结果

        爱吃拉面的小泉同学爱吃拉面的小泉同学

        王牌御史

使用print方法输出

    PrintWriter pw = new PrintWriter("d:\\pw.txt");

    pw.println("这是一个换行输出");
    // 将字符'A'对应ASCII码写入到输出流中,等于输出'A'
    pw.write(0x41);
    // 将字符串"65"写入到输出流中。
    pw.append('B').append("CDEF");
    pw.println();

    String str = "今天是";
    int mouth=5;
    int day=1;
    pw.printf("%s%d.%d", str, mouth,day);
    pw.flush();

运行结果

这是一个换行输出
ABCDEF
今天是5.1

猜你喜欢

转载自blog.csdn.net/u011863951/article/details/79968915