java IO(八):FileWriter和OutputStreamWriter和StreamEncoder


其實這三個輸出流,就是對應那三個輸入流的。

和那三個輸入流一樣,這三個流在字符輸出上也密切相關。

一、FileWriter

和輸入流一樣,也是只有幾個對應文件系統的構造方法,這里不再贅述。

二、OutputStreamWriter

和輸入流一樣,也是通過傳入的OutputStream流對StreamEncoder進行初始化,append在OutputStream流中已指定。

三、StreamEncoder

這才是字符輸出流的關鍵類(同理在實際使用中也最好使用BufferedWriter進行包裝)

這個類和StreamDecoder長得非常類似,我們來比較一下:

1)屬性域

    
StreamEncoder
   private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192; //確保流是打開狀態否則無法輸入輸出 private volatile boolean isOpen; //字符集 private Charset cs; //編碼器 private CharsetEncoder encoder; //字節緩沖區 private ByteBuffer bb; //輸出流 private final OutputStream out; //信道,對於輸入流,緩沖區從信道中取數據,對於輸出流,緩沖區輸出內容到信道(應該是這樣,信道這個概念還未理解) private WritableByteChannel ch; //為保證讀入的字符不亂嗎,則每次要讀入兩個字符 private boolean haveLeftoverChar; private char leftoverChar; //字符緩沖區——專用於左側字符操作 private CharBuffer lcb;
  
StreamDecoder
  //
定義兩個表示字節緩沖區大小的整型常量,最小為32,默認為8192 private static final int MIN_BYTE_BUFFER_SIZE = 32; private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192; //表示流是否被打開的布爾型變量 private volatile boolean isOpen; //在read里用到,read方法返回一個字符,但實際上是讀取2個字符,剩余的一個字符會保存到leftoverChar里,haveLeftoverChar表示是否有這個剩余多出來的字符。 private boolean haveLeftoverChar; private char leftoverChar; //這個和下面的ReadableByteChannel意思是信道,但還不知道有什么用 private static volatile boolean channelsAvailable = true; //字符集 private Charset cs; //解碼器 private CharsetDecoder decoder; //字節緩沖對象 private ByteBuffer bb; //字節輸入流 private InputStream in; private ReadableByteChannel ch;

2)構造方法

    private StreamEncoder(OutputStream var1, Object var2, Charset var3) {
        this(var1, var2, var3.newEncoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE));
    }

    private StreamEncoder(OutputStream var1, Object var2, CharsetEncoder var3) {
        super(var2);
        this.isOpen = true;
        this.haveLeftoverChar = false;
        this.lcb = null;
        this.out = var1;
        this.ch = null;
        this.cs = var3.charset();
        this.encoder = var3;
        if (this.ch == null) {
            this.bb = ByteBuffer.allocate(8192);
        }

    }

    private StreamEncoder(WritableByteChannel var1, CharsetEncoder var2, int var3) {
        this.isOpen = true;
        this.haveLeftoverChar = false;
        this.lcb = null;
        this.out = null;
        this.ch = var1;
        this.cs = var2.charset();
        this.encoder = var2;
        this.bb = ByteBuffer.allocate(var3 < 0 ? 8192 : var3);
    }

和StreamDecoder區別不大,不再贅述

3)forOutputStreamWriter()

    public static StreamEncoder forOutputStreamWriter(OutputStream var0, Object var1, String var2) throws UnsupportedEncodingException {
        String var3 = var2;
        if (var2 == null) {
            var3 = Charset.defaultCharset().name();
        }

        try {
            if (Charset.isSupported(var3)) {
                return new StreamEncoder(var0, var1, Charset.forName(var3));
            }
        } catch (IllegalCharsetNameException var5) {
        }

        throw new UnsupportedEncodingException(var3);
    }

    public static StreamEncoder forOutputStreamWriter(OutputStream var0, Object var1, Charset var2) {
        return new StreamEncoder(var0, var1, var2);
    }

    public static StreamEncoder forOutputStreamWriter(OutputStream var0, Object var1, CharsetEncoder var2) {
        return new StreamEncoder(var0, var1, var2);

也和StreamDecoder區別不大。

4)write()

相較StreamDecoder的read()方法,write()方法要簡單許多,就是直接判斷offset和len的合法性,然后調用implWrite()

public void write(int var1) throws IOException {
        char[] var2 = new char[]{(char)var1};
        this.write((char[])var2, 0, 1);
    }

    public void write(char[] var1, int var2, int var3) throws IOException {
        synchronized(this.lock) {
            this.ensureOpen();
            if (var2 >= 0 && var2 <= var1.length && var3 >= 0 && var2 + var3 <= var1.length && var2 + var3 >= 0) {
                if (var3 != 0) {
                    this.implWrite(var1, var2, var3);
                }
            } else {
                throw new IndexOutOfBoundsException();
            }
        }
    }

    public void write(String var1, int var2, int var3) throws IOException {
        if (var3 < 0) {
            throw new IndexOutOfBoundsException();
        } else {
            char[] var4 = new char[var3];
            var1.getChars(var2, var2 + var3, var4, 0);
            this.write((char[])var4, 0, var3);
        }
    }

上下兩個方法本質就是調用中間的write(char[] var1,int var2,int var3)

對於最上面的方法,是將單個字符轉成字符數組,然后傳入中間方法;對於下面的方法,是將字符串轉成字符數組,再傳入中間方法。

中間方法var1便是那個字符數組,var2可以理解為offset,var3可以理解為length。

5)implWrite(char[] cbuf, int offset, int length)

void implWrite(char[] var1, int var2, int var3) throws IOException {
        CharBuffer var4 = CharBuffer.wrap(var1, var2, var3);
        if (this.haveLeftoverChar) {
            this.flushLeftoverChar(var4, false);
        }

        while(var4.hasRemaining()) {
            CoderResult var5 = this.encoder.encode(var4, this.bb, false);
            if (var5.isUnderflow()) {
                assert var4.remaining() <= 1 : var4.remaining();

                if (var4.remaining() == 1) {
                    this.haveLeftoverChar = true;
                    this.leftoverChar = var4.get();
                }
                break;
            }

            if (var5.isOverflow()) {
                assert this.bb.position() > 0;

                this.writeBytes();
            } else {
                var5.throwException();
            }
        }

    }

flushLeftoverChar()和writeBytes()將在(八)中說到。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM