[二十四]JavaIO之PrintWriter

 

功能简介

 
PrintWriter   向文本输出流打印对象的格式化表示形式
他与PrintStream的逻辑上功能目的是相同的–他们都想做同一件事情–更便捷的格式化打印输出
 
PrintWriter实现了PrintStream 中的所有 print 方法,除了那些用于写入原始字节的方法,对于那些字节,程序应该使用未编码的字节流进行写入
PrintStream会在换行符时自动调用自动刷新
PrintWriter在这一点上与PrintWriter不同,
只有在调用 println、printf 或 format 的其中一个方法时才可能完成此操作
类似,PrintStream   此类中的方法不会抛出 I/O 异常,可以通过 checkError() 检查是否出现错误
 
PrintWriter也是装饰器模式
只不过看起来没那么典型而已
他直接继承Writer   省略了抽象装饰器角色Decorator
PrintWriter 既充当了Decorator也是一个ConcreteDecorator
它内部包含了一个Writer out
image_5b9b0ccf_7e75
 
 

构造方法

 
他内部有一个Writer out ,而且刚才我们已经说了他是装饰器模式
所以他必然会需要一个out,你从构造方法的实际情况也可以看得出来
构造方法主要内容包括下面三部分:
    1. 首先需要一个Writer
    2. 自动刷新的标志
    3. 字符编码的设置
    对于一个Writer
    1. 他要么就是一个直接的Writer
    2. 要么是一个new OutputStreamWriter( OutputStream) 把OutputStream转换为Writer
    3. 另外,通过File或者String路径名,也可以构造FileOutputStream  ,他就是一个OutputStream,也就是下面的形式:
        new OutputStreamWriter( new FileOutputStream(File/String路径) )   
自动刷新,如果不传递,默认false
编码如果不设置,那么是系统默认
 
最根本的构造方法是
image_5b9b0ccf_47a0
最根本的为什么没有字符编码相关的?
其实, 还有一个私有的
私有的构造方法,将带有字符编码情况的进行了二次的包装
在创建 OutputStreamWriter时使用
私有的构造方法还是绕回去到上面说的这个根本的构造方法去了
image_5b9b0ccf_4548
你会从构造方法中可以看得出来
如果构造方法中指定了编码
将会经由这个私有的构造方法转发下

如果没指定将会使用我们上面说的那个最根本的形式

    public PrintWriter(Writer out,
                       boolean autoFlush) {
不指定编码的 
全部都是使用
PrintWriter(Writer out, boolean autoFlush)
image_5b9b0ccf_1287
带编码的借助于私有构造方法进行请求转发
private PrintWriter(Charset charset, File file)
image_5b9b0ccf_2318
说了那么多,其实也只还是需要记住下面这一个就好了
PrintWriter(Writer out, boolean autoFlush)
只有File参数或者String路径参数 才会设置编码的参数,
如果设置了编码的参数的话,将会在把他们转换为Writer时, 也就是 new OutputStreamWriter 中通过指定编码参数构造
 
 

Write方法

write方法的本质还是将数据写入到输出流
提供了5个版本的write
void write(char[] buf)
          将字符数组 写入
void write(char[] buf, int off, int len)
          将字符数组的某一部分  写入
void write(int c)
          将单个字符 写入
void write(String s)
          将字符串 写入
void write(String s, int off, int len)
          将字符串的某一部分 写入
 
三个基础方法,两个简化版方法
看得出来,类似PrintStream PrintWriter 也
不会抛出IOException异常
可以通过 
checkError 
方法查看
trouble
的状态 
image_5b9b0cd0_67a9
image_5b9b0cd0_5996
 
 

print(xxx) /println(xxx)

println()
通过写入行分隔符字符串终止当前行。行分隔符字符串由系统属性 line.separator 定义,不一定是单个换行符 (‘\n’)
image_5b9b0cd0_1da5
 
print(boolean)
image_5b9b0cd0_39e9 + println()  = println(boolean)
print(char)
image_5b9b0cd0_49f5 + println()  = println(char)
print(int)
image_5b9b0cd0_278d + println()  = println(int)
print(long)
image_5b9b0cd0_72bd + println()  = println(long)
print(float)
image_5b9b0cd0_2f17 + println()  = println(float)
print(double)
image_5b9b0cd0_38b7 + println()  = println(double)
print(char[])
image_5b9b0cd0_567e + println()  = println(char[])
print(String)
image_5b9b0cd0_2925 + println()  = println(String)
print(Object) image_5b9b0cd0_5968 println(String.valueOf(Object))+ println()  = println(Object)
稍微特殊,先转换为String    String.valueOf(Object)
然后print(String)+ println()
 
可以看得出来  print系列都是调用的write方法
而且,基本上是write(String s)方法
boolean 会翻译成 字符串 true 或者false,然后调用write
String 如果是null 翻译成字符串 null    然后调用write
除了Object略微特殊以外,其他所有的print 和 println结合之后可以产生对应的println(xxx)的形式
 

append

三个版本的append方法

    append(char)
    append(java.lang.CharSequence)
    append(java.lang.CharSequence, int, int)
 
内部全部都是依赖于write方法
image_5b9b0cd0_b67
 
 

printf 与 format

PrintWriter内部也有一个Formatter
image_5b9b0cd0_3ac3
printf(java.util.Locale, java.lang.String, java.lang.Object…)
printf(java.lang.String, java.lang.Object…)
format(java.util.Locale, java.lang.String, java.lang.Object…)
format(java.lang.String, java.lang.Object…)
printf借助于format
format依赖Formatter
image_5b9b0cd0_7395
jdk1.8中 format方法与PrintStream 中几乎一样的,几乎一样的,几乎一样的….
 
 
PrintWriter提供了close以及flush方法
如下图所示,依赖于内部out 的 close和flush 也没什么好说的
image_5b9b0cd0_6f9e
 

总结

 
PrintWriter 构造方法很多,提供出来的方法也很多,看起来让人眼花缭乱
其实他就是一个装饰工具类,底层逻辑也很简单
既然是工具性质的
1. 自然需要有足够便捷的构造形式,你看那么多构造方法,最终不过也就是一种形式的构造方法
2. 自然有能够有多变的输出形式才能够说是便捷的输出打印嘛
对于Writer家族的一些基本操作,基本上是沿用了Write
 
所谓的增加的便捷亮点各种print和println
也就只是使用Writer本身的write方法打印输出他们的字符 形式
转换为字符的规则为:
基本数据类型和Object 会使用String.valueOf进行转换  
字符 字符数组 String本身就是字符/字符串的形式
 
另外的一个亮点是printf 同PrintStream中的是一样的,想要弄清楚重点在于弄清楚 Formatter了
 
上面说了,他既然是装饰工具流,所以说他必然要依赖于其他的输出流
PrintWriter就是依赖Writer,他就是来给这个Writer增加更便捷的打印输出功能的
既然着重点在于格式化输出数据,那么他的关注点自然在于数据的形式,而不是在于怎么写,所以write方法都几乎不动使用的还是原来的
然后在实际的调用各种print方法的时候,在对方法的入参进行转换,换成了字符的形式而已