该类继承自FilterOutputStream,完成了Appendable,Closeable接口
该类引入了如下包:
import java.util.Formatter; import java.util.Locale; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException;
该类的类头注释如下:
/** * A <code>PrintStream</code> adds functionality to another output stream, * namely the ability to print representations of various data values * conveniently. Two other features are provided as well. Unlike other output * streams, a <code>PrintStream</code> never throws an * <code>IOException</code>; instead, exceptional situations merely set an * internal flag that can be tested via the <code>checkError</code> method. * Optionally, a <code>PrintStream</code> can be created so as to flush * automatically; this means that the <code>flush</code> method is * automatically invoked after a byte array is written, one of the * <code>println</code> methods is invoked, or a newline character or byte * (<code>'\n'</code>) is written. * * <p> All characters printed by a <code>PrintStream</code> are converted into * bytes using the platform's default character encoding. The <code>{@link * PrintWriter}</code> class should be used in situations that require writing * characters rather than bytes. * * @author Frank Yellin * @author Mark Reinhold * @since JDK1.0 */
大意如下:
PrintStream相对于其他的输出流增加了一些实用功能,即高效方便地打印出多种类型数据的表示形式
同时也提供两种额外的功能
不同于其他输出流,PrintStream从不抛出IOException;作为替代,异常情况下仅仅设置一个内部的标志位
这个标志位可以被checkError方法检测
可供选择的功能:PrintStream可以被创建为自动刷新模式,这种情况下意味着flush方法将会在byte数组被写入,或println方法被调用后,或者是被写入一个新行符(或者byte'\n')后自动调用
全部被PrintStream打印出的字符将会使用底层系统默认的字符解码方式解码为byte
PrintWriter类应该在更需要写出字符类的情况下使用
该类含有如下的成员变量:
自动刷新标志位
private final boolean autoFlush;
当前流是否报错标志位
private boolean trouble = false;
格式控制
private Formatter formatter;
内部输出流(文本和字符输出流)
private BufferedWriter textOut; private OutputStreamWriter charOut;
关闭标志位(防止多次关闭
private boolean closing = false;
该类含有如下的成员方法:
在PrintStream初始化前先显示声明requireNonNull,避免系统创建额外的依赖关系(其他的默认方法),返回对象或者空指针信息
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); } }
私有构造函数(指定自动刷新功能和输出流)
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); }
构造函数(非自动
public PrintStream(OutputStream out) { this(out, false); }
构造函数(指定自动属性
public PrintStream(OutputStream out, boolean autoFlush) { this(autoFlush, requireNonNull(out, "Null output stream")); }
构造函数(指定了编码字符集名称
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(); out.flush(); } catch (IOException x) { trouble = true; } } }
关闭输出流
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; } } }
检测错误信息
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; }
写出单个字节
public void write(int b) { try { synchronized (this) { ensureOpen(); out.write(b); if ((b == '\n') && autoFlush)//如果当前输入为新行符且开启自动刷新 out.flush(); } } catch (InterruptedIOException x) {//IO中断异常 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] == '\n') out.flush();//从FilterOutputStream继承下来的内嵌输出流,刷新输出流 } } } 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('\n') >= 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; } }
打印bool类型
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); }
打印对象
public void print(Object obj) { write(String.valueOf(obj)); }
默认打印方法,打印换行符
public void println() { newLine(); }
打印bool类后接新行符
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(); } }
输出指定格式的一串对象数据
public PrintStream printf(String format, Object ... args) { return format(format, args); }
输出指定格式的一串对象数据(包含地区敏感
public PrintStream printf(Locale l, String format, Object ... args) { return format(l, format, args); }
使用指定格式字符串和参数将格式化字符写入该字符串(默认地区
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;//返回当前流 }
指定格式和地区写入字符串
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; }
该类写入方式很简单,十分清晰,需要注意多层流的功能封装,以及打印时的及时输出。但是由于每次打印都要刷新,实际写出效率并不高,使用时需要注意。