JDK

java.io.BufferedWriterクラス

 ファイル等を書き込む際に,バッファリングを行って高速化するWriterクラスである。Writerクラスのインスタンスoutをラップしている。バッファはchar型の配列でディフォルトのサイズは8192と定義されている。

 コンストラクタは次のようなものが定義されている。一つ目のコンストラクタは,引数を上述のディフォルトバッファサイズと共に2つ目のコンストラクタへ渡している。そして,バッファサイズはnCharsというインスタンス変数に保存される。また,次に書き込む配列インデックスを表すnextCharというインスタンス変数に0がセットされる。

  • BufferedWriter(Writer out)
  • BufferedWriter(Writer out, int sz)

write(int c)メソッドはこのクラスの中では低レベルのメソッドで,int型の値をバッファに書き出す。そして,次に書き込むバッファ位置がバッファサイズを超えていたら,flushBuffer()メソッドを呼び出して,バッファをフラッシュする。

  flushBuffer() メソッドでは,ラップしているWriterクラスのwrite()メソッドを用いてバッファの内容を書き込み,次に書き込むバッファ位置を示すnextCharを0に戻す。

write(char cbuf[], int off, int len)メソッドはchar型の配列で渡されたデータをオフセットと長さを指定してバッファに書き込む。この時,長さがバッファサイズを超えている場合には,直接ラップしているWriterクラスのwriteメソッドを呼び出している。バッファサイズより大きいものを書き込もうとしたら,バッファの効果がなくなるので合理的な処理である。一方,バッファサイズより書き込むデータが短い場合はSystem.arraycopyメソッドを使って,データをバッファにコピーする。

public void write(String s, int off, int len)メソッドは,文字列をバッファに書き込む。StringクラスのgetChars()メソッドでchar型の配列に変換したものを書き込んでいるに過ぎない。

/*
 * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package java.io;
public class BufferedWriter extends Writer {
    private Writer out;
    private char cb[];
    private int nChars, nextChar;
    private static int defaultCharBufferSize = 8192;
    public BufferedWriter(Writer out) {
        this(out, defaultCharBufferSize);
    }
    public BufferedWriter(Writer out, int sz) {
        super(out);
        if (sz <= 0)
            throw new IllegalArgumentException("Buffer size <= 0");
        this.out = out;
        cb = new char[sz];
        nChars = sz;
        nextChar = 0;
    }
    private void ensureOpen() throws IOException {
        if (out == null)
            throw new IOException("Stream closed");
    }
    void flushBuffer() throws IOException {
        synchronized (lock) {
            ensureOpen();
            if (nextChar == 0)
                return;
            out.write(cb, 0, nextChar);
            nextChar = 0;
        }
    }
    public void write(int c) throws IOException {
        synchronized (lock) {
            ensureOpen();
            if (nextChar >= nChars)
                flushBuffer();
            cb[nextChar++] = (char) c;
        }
    }
    private int min(int a, int b) {
        if (a < b) return a;
        return b;
    }
    public void write(char cbuf[], int off, int len) throws IOException {
        synchronized (lock) {
            ensureOpen();
            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
                ((off + len) > cbuf.length) || ((off + len) < 0)) {
                throw new IndexOutOfBoundsException();
            } else if (len == 0) {
                return;
            }
            if (len >= nChars) {
                /* If the request length exceeds the size of the output buffer,
                   flush the buffer and then write the data directly.  In this
                   way buffered streams will cascade harmlessly. */
                flushBuffer();
                out.write(cbuf, off, len);
                return;
            }
            int b = off, t = off + len;
            while (b < t) {
                int d = min(nChars – nextChar, t – b);
                System.arraycopy(cbuf, b, cb, nextChar, d);
                b += d;
                nextChar += d;
                if (nextChar >= nChars)
                    flushBuffer();
            }
        }
    }
    public void write(String s, int off, int len) throws IOException {
        synchronized (lock) {
            ensureOpen();
            int b = off, t = off + len;
            while (b < t) {
                int d = min(nChars – nextChar, t – b);
                s.getChars(b, b + d, cb, nextChar);
                b += d;
                nextChar += d;
                if (nextChar >= nChars)
                    flushBuffer();
            }
        }
    }
    public void newLine() throws IOException {
        write(System.lineSeparator());
    }
    public void flush() throws IOException {
        synchronized (lock) {
            flushBuffer();
            out.flush();
        }
    }
    @SuppressWarnings("try")
    public void close() throws IOException {
        synchronized (lock) {
            if (out == null) {
                return;
            }
            try (Writer w = out) {
                flushBuffer();
            } finally {
                out = null;
                cb = null;
            }
        }
    }
}