thinking in java (三十二) ----- IO之 PrintWriter
阿新 • • 發佈:2018-11-16
介紹
PrintWriter 是字元型別的列印輸出流,它繼承於Writer。
PrintWriter用於向文字輸出流列印物件的格式化表示形式。它實現在 PrintStream 中的所有 print 方法。
原始碼
package java.io; import java.util.Objects; import java.util.Formatter; import java.util.Locale; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; public class PrintWriter extends Writer { protected Writer out; // 自動flush // 所謂“自動flush”,就是每次執行print(), println(), write()函式,都會呼叫flush()函式; // 而“不自動flush”,則需要我們手動呼叫flush()介面。 private final boolean autoFlush; // PrintWriter是否右產生異常。當PrintWriter有異常產生時,會被本身捕獲,並設定trouble為true private boolean trouble = false; // 用於格式化的物件 private Formatter formatter; private PrintStream psOut = null; // 行分割符 private final String lineSeparator; // 獲取csn(字符集名字)對應的Chaset private static Charset toCharset(String csn) throws UnsupportedEncodingException { Objects.requireNonNull(csn, "charsetName"); try { return Charset.forName(csn); } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) { // UnsupportedEncodingException should be thrown throw new UnsupportedEncodingException(csn); } } // 將“Writer物件out”作為PrintWriter的輸出流,預設不會自動flush,並且採用預設字符集。 public PrintWriter (Writer out) { this(out, false); } // 將“Writer物件out”作為PrintWriter的輸出流,autoFlush的flush模式,並且採用預設字符集。 public PrintWriter(Writer out, boolean autoFlush) { super(out); this.out = out; this.autoFlush = autoFlush; lineSeparator = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("line.separator")); } // 將“輸出流物件out”作為PrintWriter的輸出流,不自動flush,並且採用預設字符集。 public PrintWriter(OutputStream out) { this(out, false); } // 將“輸出流物件out”作為PrintWriter的輸出流,autoFlush的flush模式,並且採用預設字符集。 public PrintWriter(OutputStream out, boolean autoFlush) { // new OutputStreamWriter(out):將“位元組型別的輸出流”轉換為“字元型別的輸出流” // new BufferedWriter(...): 為輸出流提供緩衝功能。 this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush); // save print stream for error propagation if (out instanceof java.io.PrintStream) { psOut = (PrintStream) out; } } // 建立fileName對應的OutputStreamWriter,進而建立BufferedWriter物件;然後將該BufferedWriter作為PrintWriter的輸出流,不自動flush,採用預設字符集。 public PrintWriter(String fileName) throws FileNotFoundException { this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))), false); } // 建立fileName對應的OutputStreamWriter,進而建立BufferedWriter物件;然後將該BufferedWriter作為PrintWriter的輸出流,不自動flush,採用字符集charset。 private PrintWriter(Charset charset, File file) throws FileNotFoundException { this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)), false); } // 建立fileName對應的OutputStreamWriter,進而建立BufferedWriter物件;然後將該BufferedWriter作為PrintWriter的輸出流,不自動flush,採用csn字符集。 public PrintWriter(String fileName, String csn) throws FileNotFoundException, UnsupportedEncodingException { this(toCharset(csn), new File(fileName)); } // 建立file對應的OutputStreamWriter,進而建立BufferedWriter物件;然後將該BufferedWriter作為PrintWriter的輸出流,不自動flush,採用預設字符集。 public PrintWriter(File file) throws FileNotFoundException { this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))), false); } // 建立file對應的OutputStreamWriter,進而建立BufferedWriter物件;然後將該BufferedWriter作為PrintWriter的輸出流,不自動flush,採用csn字符集。 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"); } // flush“PrintWriter輸出流中的資料”。 public void flush() { try { synchronized (lock) { ensureOpen(); out.flush(); } } catch (IOException x) { trouble = true; } } public void close() { try { synchronized (lock) { if (out == null) return; out.close(); out = null; } } catch (IOException x) { trouble = true; } } // flush“PrintWriter輸出流緩衝中的資料”,並檢查錯誤 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; } // 將字元c寫入到“PrintWriter輸出流”中。c雖然是int型別,但實際只會寫入一個字元 public void write(int c) { try { synchronized (lock) { ensureOpen(); out.write(c); } } catch (InterruptedIOException x) { Thread.currentThread().interrupt(); } catch (IOException x) { trouble = true; } } // 將“buf中從off開始的len個字元”寫入到“PrintWriter輸出流”中。 public void write(char buf[], int off, int len) { try { synchronized (lock) { ensureOpen(); out.write(buf, off, len); } } catch (InterruptedIOException x) { Thread.currentThread().interrupt(); } catch (IOException x) { trouble = true; } } // 將“buf中的全部資料”寫入到“PrintWriter輸出流”中。 public void write(char buf[]) { write(buf, 0, buf.length); } // 將“字串s中從off開始的len個字元”寫入到“PrintWriter輸出流”中。 public void write(String s, int off, int len) { try { synchronized (lock) { ensureOpen(); out.write(s, off, len); } } catch (InterruptedIOException x) { Thread.currentThread().interrupt(); } catch (IOException x) { trouble = true; } } // 將“字串s”寫入到“PrintWriter輸出流”中。 public void write(String s) { write(s, 0, s.length()); } // 將“換行符”寫入到“PrintWriter輸出流”中。 private void newLine() { try { synchronized (lock) { ensureOpen(); out.write(lineSeparator); if (autoFlush) out.flush(); } } catch (InterruptedIOException x) { Thread.currentThread().interrupt(); } catch (IOException x) { trouble = true; } } // 將“boolean資料對應的字串”寫入到“PrintWriter輸出流”中,print實際呼叫的是write函式 public void print(boolean b) { write(b ? "true" : "false"); } // 將“字元c對應的字串”寫入到“PrintWriter輸出流”中,print實際呼叫的是write函式 public void print(char c) { write(c); } // 將“int資料i對應的字串”寫入到“PrintWriter輸出流”中,print實際呼叫的是write函式 public void print(int i) { write(String.valueOf(i)); } // 將“long型資料l對應的字串”寫入到“PrintWriter輸出流”中,print實際呼叫的是write函式 public void print(long l) { write(String.valueOf(l)); } // 將“float資料f對應的字串”寫入到“PrintWriter輸出流”中,print實際呼叫的是write函式 public void print(float f) { write(String.valueOf(f)); } // 將“double資料d對應的字串”寫入到“PrintWriter輸出流”中,print實際呼叫的是write函式 public void print(double d) { write(String.valueOf(d)); } // 將“字元陣列s”寫入到“PrintWriter輸出流”中,print實際呼叫的是write函式 public void print(char s[]) { write(s); } // 將“字串資料s”寫入到“PrintWriter輸出流”中,print實際呼叫的是write函式 public void print(String s) { if (s == null) { s = "null"; } write(s); } // 將“物件obj對應的字串”寫入到“PrintWriter輸出流”中,print實際呼叫的是write函式 public void print(Object obj) { write(String.valueOf(obj)); } // 將“換行符”寫入到“PrintWriter輸出流”中,println實際呼叫的是write函式 public void println() { newLine(); } // 將“boolean資料對應的字串+換行符”寫入到“PrintWriter輸出流”中,println實際呼叫的是write函式 public void println(boolean x) { synchronized (lock) { print(x); println(); } } // 將“字元x對應的字串+換行符”寫入到“PrintWriter輸出流”中,println實際呼叫的是write函式 public void println(char x) { synchronized (lock) { print(x); println(); } } // 將“int資料對應的字串+換行符”寫入到“PrintWriter輸出流”中,println實際呼叫的是write函式 public void println(int x) { synchronized (lock) { print(x); println(); } } // 將“long資料對應的字串+換行符”寫入到“PrintWriter輸出流”中,println實際呼叫的是write函式 public void println(long x) { synchronized (lock) { print(x); println(); } } // 將“float資料對應的字串+換行符”寫入到“PrintWriter輸出流”中,println實際呼叫的是write函式 public void println(float x) { synchronized (lock) { print(x); println(); } } // 將“double資料對應的字串+換行符”寫入到“PrintWriter輸出流”中,println實際呼叫的是write函式 public void println(double x) { synchronized (lock) { print(x); println(); } } // 將“字元陣列x+換行符”寫入到“PrintWriter輸出流”中,println實際呼叫的是write函式 public void println(char x[]) { synchronized (lock) { print(x); println(); } } // 將“字串x+換行符”寫入到“PrintWriter輸出流”中,println實際呼叫的是write函式 public void println(String x) { synchronized (lock) { print(x); println(); } } // 將“物件o對應的字串+換行符”寫入到“PrintWriter輸出流”中,println實際呼叫的是write函式 public void println(Object x) { String s = String.valueOf(x); synchronized (lock) { print(s); println(); } } // 將“資料args”根據“預設Locale值(區域屬性)”按照format格式化,並寫入到“PrintWriter輸出流”中 public PrintWriter printf(String format, Object ... args) { return format(format, args); } // 將“資料args”根據“Locale值(區域屬性)”按照format格式化,並寫入到“PrintWriter輸出流”中 public PrintWriter printf(Locale l, String format, Object ... args) { return format(l, format, args); } // 根據“預設的Locale值(區域屬性)”來格式化資料 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; } // 將“字元序列的全部字元”追加到“PrintWriter輸出流中” public PrintWriter append(CharSequence csq) { if (csq == null) write("null"); else write(csq.toString()); return this; } // 將“字元序列從start(包括)到end(不包括)的全部字元”追加到“PrintWriter輸出流中” public PrintWriter append(CharSequence csq, int start, int end) { CharSequence cs = (csq == null ? "null" : csq); write(cs.subSequence(start, end).toString()); return this; } // 將“字元c”追加到“PrintWriter輸出流中” public PrintWriter append(char c) { write(c); return this; } }
示例程式碼
import java.io.PrintWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; /** * PrintWriter 的示例程式 * * @author skywang */ public class PrintWriterTest { public static void main(String[] args) { // 下面3個函式的作用都是一樣:都是將字母“abcde”寫入到檔案“file.txt”中。 // 任選一個執行即可! testPrintWriterConstrutor1() ; //testPrintWriterConstrutor2() ; //testPrintWriterConstrutor3() ; // 測試write(), print(), println(), printf()等介面。 testPrintWriterAPIS() ; } /** * PrintWriter(OutputStream out) 的測試函式 * * 函式的作用,就是將字母“abcde”寫入到檔案“file.txt”中 */ private static void testPrintWriterConstrutor1() { final char[] arr={'a', 'b', 'c', 'd', 'e' }; try { // 建立檔案“file.txt”的File物件 File file = new File("file.txt"); // 建立檔案對應FileOutputStream PrintWriter out = new PrintWriter( new FileOutputStream(file)); // 將“位元組陣列arr”全部寫入到輸出流中 out.write(arr); // 關閉輸出流 out.close(); } catch (IOException e) { e.printStackTrace(); } } /** * PrintWriter(File file) 的測試函式 * * 函式的作用,就是將字母“abcde”寫入到檔案“file.txt”中 */ private static void testPrintWriterConstrutor2() { final char[] arr={'a', 'b', 'c', 'd', 'e' }; try { File file = new File("file.txt"); PrintWriter out = new PrintWriter(file); out.write(arr); out.close(); } catch (IOException e) { e.printStackTrace(); } } /** * PrintWriter(String fileName) 的測試函式 * * 函式的作用,就是將字母“abcde”寫入到檔案“file.txt”中 */ private static void testPrintWriterConstrutor3() { final char[] arr={'a', 'b', 'c', 'd', 'e' }; try { PrintWriter out = new PrintWriter("file.txt"); out.write(arr); out.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 測試write(), print(), println(), printf()等介面。 */ private static void testPrintWriterAPIS() { final char[] arr={'a', 'b', 'c', 'd', 'e' }; try { // 建立檔案對應FileOutputStream PrintWriter out = new PrintWriter("other.txt"); // 將字串“hello PrintWriter”+回車符,寫入到輸出流中 out.println("hello PrintWriter"); // 將0x41寫入到輸出流中 // 0x41對應ASCII碼的字母'A',也就是寫入字元'A' out.write(0x41); // 將字串"65"寫入到輸出流中。 // out.print(0x41); 等價於 out.write(String.valueOf(0x41)); out.print(0x41); // 將字元'B'追加到輸出流中 out.append('B').append("CDEF"); // 將"CDE is 5" + 回車 寫入到輸出流中 String str = "GHI"; int num = 5; out.printf("%s is %d\n", str, num); out.close(); } catch (IOException e) { e.printStackTrace(); } } }
執行上面的程式碼,會在原始碼所在目錄生成兩個檔案“file.txt”和“other.txt”。
file.txt的內容如下:
abcde
other.txt的內容如下:
hello PrintWriter
A65BCDEFGHI is 5