[重學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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章