首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java IO 記憶體流:CharArrayWriter 字元陣列輸出流完整指南

     編輯:Java 相關知識

核心定位:記憶體內字元累積器

CharArrayWriter 是字元導向的記憶體輸出流,繼承自 Writer。它內部維護一個動態擴充的字元陣列(char[] buf),將寫入的字元累積在記憶體中,支援轉換為字串、字元陣列,或輸出至其他 Writer。預設初始容量 32 字元,自動按 2 倍擴充。適合構建字串、產生文字報表、單元測試捕獲輸出等場景。

關鍵 API 分類


// 建構子
CharArrayWriter()                          // 預設 32 字元初始容量
CharArrayWriter(int initialSize)           // 指定初始容量

// 寫入(繼承自 Writer,內部委派給 buf)
void write(int c)                          // 單字元
void write(char[] cbuf, int off, int len)  // 字元陣列片段
void write(String str, int off, int len)   // 字串片段

// Appendable 介面(支援鏈式呼叫)
CharArrayWriter append(char c)
CharArrayWriter append(CharSequence csq)
CharArrayWriter append(CharSequence csq, int start, int end)

// 狀態查詢
int size()                                 // 目前累積字元數
char[] toCharArray()                       // 複製並回傳字元陣列
String toString()                          // 轉換為字串(等同 new String(buf, 0, count))

// 輸出至其他 Writer
void writeTo(Writer out) throws IOException

// 重置與關閉
void reset()                               // 清空緩衝區(count=0),容量保留
void close()                               // 無實際作用,標準介面相容
void flush()                               // 無實際作用,標準介面相容

原始碼核心實現

動態擴充邏輯


public class CharArrayWriter extends Writer {
    protected char[] buf;      // 字元緩衝區
    protected int count;       // 有效字元數
    
    public CharArrayWriter() {
        this(32);
    }
    
    public CharArrayWriter(int initialSize) {
        if (initialSize < 0) throw new IllegalArgumentException("Negative initial size");
        buf = new char[initialSize];
    }
    
    // 單字元寫入:自動擴充
    public void write(int c) {
        synchronized (lock) {
            int newCount = count + 1;
            if (newCount > buf.length) {
                buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newCount));
            }
            buf[count] = (char) c;
            count = newCount;
        }
    }
    
    // 陣列寫入:批次複製與擴充
    public void write(char[] cbuf, int off, int len) {
        if ((off < 0) || (off > cbuf.length) || (len < 0) || 
            ((off + len) > cbuf.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        }
        if (len == 0) return;
        synchronized (lock) {
            int newCount = count + len;
            if (newCount > buf.length) {
                buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newCount));
            }
            System.arraycopy(cbuf, off, buf, count, len);
            count = newCount;
        }
    }
    
    // 輸出至其他 Writer
    public void writeTo(Writer out) throws IOException {
        synchronized (lock) {
            out.write(buf, 0, count);
        }
    }
    
    public void reset() {
        count = 0;  // 僅重置計數,陣列保留供下次複用
    }
}

實戰範例:高效字串構建與測試捕獲


import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class CharArrayWriterDemo {
    public static void main(String[] args) {
        demoBasicUsage();
        demoTestCapture();
        demoJsonBuilding();
    }
    
    // 基本用法:寫入、轉換、重置
    private static void demoBasicUsage() {
        CharArrayWriter caw = new CharArrayWriter(64);
        
        caw.write('A');
        caw.write("BC");
        caw.write("DEFGHIJ".toCharArray(), 1, 3);  // "EFG"
        caw.append('0').append("123456789").append("APPEND", 2, 5);  // "PPE"
        
        System.out.println("內容: " + caw);           // toString()
        System.out.println("長度: " + caw.size());     // 22
        System.out.println("陣列: " + new String(caw.toCharArray()));
        
        // 複用:重置後繼續寫入
        caw.reset();
        caw.write("重複使用緩衝區");
        System.out.println("重置後: " + caw);
    }
    
    // 單元測試:捕獲 System.out / logger 輸出
    private static void demoTestCapture() {
        CharArrayWriter captured = new CharArrayWriter();
        PrintWriter testOut = new PrintWriter(captured);
        
        // 模擬被測代碼寫入標準輸出
        testOut.println("INFO: 服務啟動");
        testOut.printf("DEBUG: 連接池大小 = %d%n", 10);
        testOut.println("WARN: 配置項缺失,使用預設值");
        testOut.flush();
        
        String output = captured.toString();
        System.out.println("=== 捕獲輸出 ===");
        System.out.print(output);
        
        // 斷言驗證
        assert output.contains("服務啟動");
        assert output.contains("連接池大小 = 10");
        System.out.println("斷言通過");
    }
    
    // 手工構建 JSON(無依賴場景)
    private static void demoJsonBuilding() {
        CharArrayWriter caw = new CharArrayWriter(256);
        
        caw.write('{');
        appendJsonField(caw, "id", 12345);
        caw.write(',');
        appendJsonField(caw, "name", "產品名稱");
        caw.write(',');
        appendJsonField(caw, "price", 299.9);
        caw.write(',');
        appendJsonArray(caw, "tags", new String[]{"熱銷", "新品", "推薦"});
        caw.write('}');
        
        String json = caw.toString();
        System.out.println("構建 JSON: " + json);
    }
    
    private static void appendJsonField(CharArrayWriter caw, String key, Object value) {
        caw.write('"').write(key).write("\":");
        if (value instanceof String) {
            caw.write('"').write((String) value).write('"');
        } else {
            caw.write(String.valueOf(value));
        }
    }
    
    private static void appendJsonArray(CharArrayWriter caw, String key, String[] values) {
        caw.write('"').write(key).write("\":[");
        for (int i = 0; i < values.length; i++) {
            if (i > 0) caw.write(',');
            caw.write('"').write(values[i]).write('"');
        }
        caw.write(']');
    }
}

CharArrayWriter vs StringBuilder vs StringBuffer

特性CharArrayWriterStringBuilderStringBuffer
介面Writer / AppendableAppendable / CharSequenceAppendable / CharSequence
執行緒安全✅ (synchronized)❌✅ (synchronized)
輸出目標可 writeTo(Writer)僅 toString()僅 toString()
API 風格流式 write/flush/closeappend/insert/deleteappend/insert/delete
適用場景需 Writer 介面、輸出轉導、測試捕獲一般字串構建(單執行緒)多執行緒字串構建(較少用)
效能略低(同步開銷)最高中等

最佳實踐建議

  1. 預估容量:大概知道最終大小時,建構子指定 initialSize 避免多次擴充複製。
  2. 善用 reset() 複用:循環處理任務時,reset() 保留陣列容量,減少 GC 壓力。
  3. 輸出轉導場景首選:需將輸出導向 Writer 介面(如 PrintWriter、BufferedWriter、第三方庫)時,CharArrayWriter 是天然橋樑。
  4. 測試捕獲標準輸出:配合 System.setOut(new PrintWriter(charArrayWriter)) 進行單元測試斷言。
  5. 大字串構建優先 StringBuilder:單執行緒、無 Writer 介面需求時,StringBuilder 效能更優。

常見誤區

  • 以為 close() 會釋放記憶體:close() 是空實現,reset() 才清空內容(但保留陣列),徹底釋放需讓物件失去引用等待 GC。
  • 直接操作 toCharArray() 回傳的陣列:回傳的是複製品,修改不影響內部狀態;但頻繁呼叫會產生大量陣列複製。
  • 多執行緒寫入未同步:雖方法有 synchronized,但複合操作(如檢查 size 再寫入)需外層同步。

CharArrayWriter 是記憶體字元累積的流式工具,掌握其動態擴充、writeTo() 轉導與 reset() 複用特性,能在測試捕獲、文字報表生成、介面適配等場景發揮獨特價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved