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

10人阅读 评论(0) 收藏 举报
分类:

[重学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
查看评论

Java基础核心技术:IO(day15-day16)

本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量最大、案例最多、实战性最强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。
  • 2015年05月11日 14:15

Java IO _打印流

掌握打印流的操作 掌握格式化输出 1、打印流 在整个 IO 包中,打印流是输出信息最方便的类,主要包含字节打印流(PrintStream) 和字符打印流(PrintWriter) . 打印流提供...
  • hanshileiai
  • hanshileiai
  • 2011-08-24 10:48:11
  • 6621

IO流——文件操作流之字符输出流FileWriter

package com.io.ioDemo; import java.io.File; import java.io.FileWriter; import java.io.IOException; ...
  • u012369385
  • u012369385
  • 2016-08-16 17:55:14
  • 2019

Java精选笔记_IO流(字符输入输出流、字符文件输入输出流、字符流的缓冲区)

字符流 Reader是字符输入流的基类,用于从某个源设备读取字符 Writer是字符输出流,用于向某个目标设备写入字符 字符流操作文件 字符输入流FileReader,通过此流可以从关...
  • xiaoye142034
  • xiaoye142034
  • 2017-07-09 23:48:45
  • 333

JAVA IO流 输出乱码问题解决

在通过IO流,把文件下的内容输入到控制台或者其他的文件中的时候,里面的汉字会发生乱码 解决的方法是通过 InputStreamReader或者InputStreamWriter下面的字符集转换的方法...
  • zidan_2011
  • zidan_2011
  • 2012-02-20 12:49:25
  • 8313

Java IO流学习总结一:输入输出流

Java IO流学习总结一:输入输出流 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/53761199 本文出自【赵彦军的...
  • zhaoyanjun6
  • zhaoyanjun6
  • 2017-01-09 19:49:50
  • 6922

java io流详解(二)对象输入输出流

1.对象输入输出流 ObjectOutputStream和ObjectInputStream可以用来实现对象序列化和反序列化操作。一般操作对象时,对象是存在内存中的,如果希望将对象保存在硬盘上,或者...
  • kaishizhangcheng
  • kaishizhangcheng
  • 2016-09-08 21:46:27
  • 3705

java io输出的编码问题

今天在做应用错误日志输出时,使用以下的写法,输出中文时乱码 File file = new File(ERRORLOG_PATH_SDCARD_DIR, needWriteFiel + E...
  • haukey
  • haukey
  • 2012-11-19 14:53:52
  • 11361

Java 输出流中的flush方法

java中的IO流中的输出流一般都有flush这个操作,这个操作的作用是强制将缓存中的输出流(字节流,字符流等)强制输出。为什么会有这么个方法啊?因为输出流在进行输出时,比如像某个文件中写入内容,其实...
  • jiyangsb
  • jiyangsb
  • 2016-03-25 22:33:16
  • 7117

【Java基础知识】IO流--标准输入输出流、打印流PrintStream

PrintStream
  • zhuwenchao90
  • zhuwenchao90
  • 2017-01-21 22:39:28
  • 666
    个人资料
    等级:
    访问量: 236
    积分: 126
    排名: 117万+
    文章分类
    文章存档