程序员潇然 发表于 2022-8-26 16:22:47

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

!(data/attachment/forum/202208/26/160321dgid4g10yszdoj08.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

### 构造方法

他内部有一个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

编码如果不设置,那么是系统默认

最根本的构造方法是

!(data/attachment/forum/202208/26/160457n7hig91qpqgxn9b9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

最基础的这一个,为什么没有字符编码相关的?
其实, 还有一个私有的
私有的构造方法,将带有字符编码情况的进行了二次的包装
在创建 OutputStreamWriter时使用
私有的构造方法还是绕回去到上面说的这个基础的构造方法去了

!(data/attachment/forum/202208/26/160529kh0fsvac0awpp00q.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

你会从构造方法中可以看得出来
如果构造方法中指定了编码
将会经由这个私有的构造方法转发下

如果没指定将会使用我们上面说的那个最根本的形式
public PrintWriter(Writer out,
boolean autoFlush) {

不指定编码的
全部都是使用PrintWriter(Writer out, boolean autoFlush)

!(data/attachment/forum/202208/26/160659z1wwgewe643tuyuu.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

带编码的借助于私有构造方法进行请求转发
private PrintWriter(Charset charset, File file)

!(data/attachment/forum/202208/26/160714gxxshdxrrmxsrrrx.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

说了那么多,其实也只还是需要记住下面这一个就好了
PrintWriter(Writer out, boolean autoFlush)
只有File参数或者String路径参数 才会设置编码的参数,
如果设置了编码的参数的话,将会在把他们转换为Writer时,也就是 new OutputStreamWriter 中通过指定编码参数构造

### Write方法

write方法的本质还是将数据写入到输出流
提供了5个版本的write

```java
//将字符数组 写入
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 的状态

!(data/attachment/forum/202208/26/160918er2bh72iswvfhjkb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

!(data/attachment/forum/202208/26/160926fkl5jsmlsrjtns7l.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

### print(xxx) /println(xxx)

#### println()

通过写入行分隔符字符串终止当前行。行分隔符字符串由系统属性 line.separator 定义,不一定是单个换行符 ('\n')

!(data/attachment/forum/202208/26/161004dtef7ii3q5844283.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

#### print(xxx)

**print(xxx)+ println() = println(xxx)**

println(Object)稍微特殊,其他的都是符合规则

```java
    /**
   * Prints a boolean value.The string produced by <code>{@link
   * java.lang.String#valueOf(boolean)}</code> is translated into bytes
   * according to the platform's default character encoding, and these bytes
   * are written in exactly the manner of the <code>{@link
   * #write(int)}</code> method.
   *
   * @param      b   The <code>boolean</code> to be printed
   */
    public void print(boolean b) {
      write(b ? "true" : "false");
    }

    /**
   * Prints a character.The character is translated into one or more bytes
   * according to the platform's default character encoding, and these bytes
   * are written in exactly the manner of the <code>{@link
   * #write(int)}</code> method.
   *
   * @param      c   The <code>char</code> to be printed
   */
    public void print(char c) {
      write(c);
    }

    /**
   * Prints an integer.The string produced by <code>{@link
   * java.lang.String#valueOf(int)}</code> is translated into bytes according
   * to the platform's default character encoding, and these bytes are
   * written in exactly the manner of the <code>{@link #write(int)}</code>
   * method.
   *
   * @param      i   The <code>int</code> to be printed
   * @see      java.lang.Integer#toString(int)
   */
    public void print(int i) {
      write(String.valueOf(i));
    }

    /**
   * Prints a long integer.The string produced by <code>{@link
   * java.lang.String#valueOf(long)}</code> is translated into bytes
   * according to the platform's default character encoding, and these bytes
   * are written in exactly the manner of the <code>{@link #write(int)}</code>
   * method.
   *
   * @param      l   The <code>long</code> to be printed
   * @see      java.lang.Long#toString(long)
   */
    public void print(long l) {
      write(String.valueOf(l));
    }

    /**
   * Prints a floating-point number.The string produced by <code>{@link
   * java.lang.String#valueOf(float)}</code> is translated into bytes
   * according to the platform's default character encoding, and these bytes
   * are written in exactly the manner of the <code>{@link #write(int)}</code>
   * method.
   *
   * @param      f   The <code>float</code> to be printed
   * @see      java.lang.Float#toString(float)
   */
    public void print(float f) {
      write(String.valueOf(f));
    }

    /**
   * Prints a double-precision floating-point number.The string produced by
   * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
   * bytes according to the platform's default character encoding, and these
   * bytes are written in exactly the manner of the <code>{@link
   * #write(int)}</code> method.
   *
   * @param      d   The <code>double</code> to be printed
   * @see      java.lang.Double#toString(double)
   */
    public void print(double d) {
      write(String.valueOf(d));
    }

    /**
   * Prints an array of characters.The characters are converted into bytes
   * according to the platform's default character encoding, and these bytes
   * are written in exactly the manner of the <code>{@link #write(int)}</code>
   * method.
   *
   * @param      s   The array of chars to be printed
   *
   * @throwsNullPointerExceptionIf <code>s</code> is <code>null</code>
   */
    public void print(char s[]) {
      write(s);
    }

    /**
   * Prints a string.If the argument is <code>null</code> then the string
   * <code>"null"</code> is printed.Otherwise, the string's characters are
   * converted into bytes according to the platform's default character
   * encoding, and these bytes are written in exactly the manner of the
   * <code>{@link #write(int)}</code> method.
   *
   * @param      s   The <code>String</code> to be printed
   */
    public void print(String s) {
      if (s == null) {
            s = "null";
      }
      write(s);
    }

    /**
   * Prints an object.The string produced by the <code>{@link
   * java.lang.String#valueOf(Object)}</code> method is translated into bytes
   * according to the platform's default character encoding, and these bytes
   * are written in exactly the manner of the <code>{@link #write(int)}</code>
   * method.
   *
   * @param      obj   The <code>Object</code> to be printed
   * @see      java.lang.Object#toString()
   */
    public void print(Object obj) {
      write(String.valueOf(obj));
    }

```

```java

    /**
   * Prints a boolean value and then terminates the line.This method behaves
   * as though it invokes <code>{@link #print(boolean)}</code> and then
   * <code>{@link #println()}</code>.
   *
   * @param x the <code>boolean</code> value to be printed
   */
    public void println(boolean x) {
      synchronized (lock) {
            print(x);
            println();
      }
    }

    /**
   * Prints a character and then terminates the line.This method behaves as
   * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
   * #println()}</code>.
   *
   * @param x the <code>char</code> value to be printed
   */
    public void println(char x) {
      synchronized (lock) {
            print(x);
            println();
      }
    }

    /**
   * Prints an integer and then terminates the line.This method behaves as
   * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
   * #println()}</code>.
   *
   * @param x the <code>int</code> value to be printed
   */
    public void println(int x) {
      synchronized (lock) {
            print(x);
            println();
      }
    }

    /**
   * Prints a long integer and then terminates the line.This method behaves
   * as though it invokes <code>{@link #print(long)}</code> and then
   * <code>{@link #println()}</code>.
   *
   * @param x the <code>long</code> value to be printed
   */
    public void println(long x) {
      synchronized (lock) {
            print(x);
            println();
      }
    }

    /**
   * Prints a floating-point number and then terminates the line.This method
   * behaves as though it invokes <code>{@link #print(float)}</code> and then
   * <code>{@link #println()}</code>.
   *
   * @param x the <code>float</code> value to be printed
   */
    public void println(float x) {
      synchronized (lock) {
            print(x);
            println();
      }
    }

    /**
   * Prints a double-precision floating-point number and then terminates the
   * line.This method behaves as though it invokes <code>{@link
   * #print(double)}</code> and then <code>{@link #println()}</code>.
   *
   * @param x the <code>double</code> value to be printed
   */
    public void println(double x) {
      synchronized (lock) {
            print(x);
            println();
      }
    }

    /**
   * Prints an array of characters and then terminates the line.This method
   * behaves as though it invokes <code>{@link #print(char[])}</code> and then
   * <code>{@link #println()}</code>.
   *
   * @param x the array of <code>char</code> values to be printed
   */
    public void println(char x[]) {
      synchronized (lock) {
            print(x);
            println();
      }
    }

    /**
   * Prints a String and then terminates the line.This method behaves as
   * though it invokes <code>{@link #print(String)}</code> and then
   * <code>{@link #println()}</code>.
   *
   * @param x the <code>String</code> value to be printed
   */
    public void println(String x) {
      synchronized (lock) {
            print(x);
            println();
      }
    }

    /**
   * Prints an Object and then terminates the line.This method calls
   * at first String.valueOf(x) to get the printed object's string value,
   * then behaves as
   * though it invokes <code>{@link #print(String)}</code> and then
   * <code>{@link #println()}</code>.
   *
   * @param xThe <code>Object</code> to be printed.
   */
    public void println(Object x) {
      String s = String.valueOf(x);
      synchronized (lock) {
            print(s);
            println();
      }
    }
```

print系列都是调用的write方法
而且,基本上是write(String s)方法
boolean 会翻译成 字符串 true 或者false,然后调用write
String 如果是null 翻译成字符串 null    然后调用write
除了Object略微特殊以外,其他所有的print 和 println结合之后可以产生对应的println(xxx)的效果形式

### append

三个版本的append方法

```java
append(char);
append(java.lang.CharSequence);
append(java.lang.CharSequence, int, int);
```

内部全部都是依赖于write方法

!(data/attachment/forum/202208/26/161937ba4spzbvtzt2enet.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

### printf 与 format

PrintWriter内部也有一个Formatter

!(data/attachment/forum/202208/26/161956svaymczvktxmbsio.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

```java
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

!(data/attachment/forum/202208/26/162050aznx9niiyktyik4x.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

**jdk1.8中 format方法与PrintStream 中几乎一样的,几乎一样的,几乎一样的....**


### close以及flush

PrintWriter提供了close以及flush方法
如下图所示,依赖于内部out 的 close和flush 也没什么好说的

!(data/attachment/forum/202208/26/162139jjpe4ci344ziiiii.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")


### 总结

PrintWriter 构造方法很多,提供出来的方法也很多,看起来让人眼花缭乱
其实他就是一个装饰工具类,底层逻辑也很简单
既然是工具性质的

1. 自然需要有足够便捷的构造形式,你看那么多构造方法,最终不过也就是一种形式的构造方法
2. 自然有能够有多变的输出形式才能够说是便捷的输出打印嘛
   对于Writer家族的一些基本操作,基本上是沿用了Write

所谓的增加的便捷亮点各种print和println
也就只是使用Writer本身的write方法打印输出他们的字符 形式


转换为字符的规则为:
基本数据类型和Object 会使用String.valueOf进行转换
字符 字符数组 String本身就是字符/字符串的形式

另外的一个亮点是printf 同PrintStream中的是一样的,想要弄清楚重点在于弄清楚 Formatter了

他既然是装饰工具流,所以说他必然要依赖于其他的输出流
PrintWriter就是依赖Writer,他就是来给这个Writer增加更便捷的打印输出功能的
既然着重点在于格式化输出数据,那么他的关注点自然在于数据的形式,而不是在于怎么写,所以write方法都几乎不动使用的还是原来的
然后在实际的调用各种print方法的时候,在对方法的入参进行转换,换成了字符的形式而已

!(data/attachment/forum/202206/16/141330jha7st9soow8772i.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "common_log.png")
`转载务必注明出处:程序员潇然,疯狂的字节X,https://crazybytex.com/thread-161-1-1.html `
页: [1]
查看完整版本: JavaIO之PrintWriter(二十五)