JDK

java.io.Consoleクラス

java.io.Consoleクラスはコマンドラインでインタラクティブな操作を行う際のインタフェースを提供する。ソースコードの中央よりやや下にインスタンス変数が宣言されている。コンストラクタはソースコードの末尾に置かれており,privateで宣言されているため,外部からインスタンスを作成することはできなくなっている。インスタンスはSystem.console()メソッドで取得するようにドキュメントに記載されている。

 writer()メソッドはコンソール画面に対して出力するためのPrintWriterを返す。reader()メソッドはコンソール画面から読み込むためのReaderを返す。printf(String format, Object … args)メソッドは,C言語のprintf()関数風の編集を行って出力する。format(String fmt, Object …args)メソッドはjava.text.Formatクラスを用いて書式化して出力する。

readLine(String fmt, Object … args)メソッドでは,改行コードが現れるまでコンソールから文字列を読み込む。一旦char[]配列に1文字ずつ読み込んだ後,String型へ変換している。与えられた引数はコンソール画面に出力される。内部でprivateなreadline()メソッドを使用している。 readline() メソッドでは,バッファからchar[]配列にデータを読み込む。末尾にある’\r’あるいは’\n’を削除して新たなchar[]配列に内容をコピーして返している。

readPassword(String fmt, Object … args)メソッドはパスワードを読み込むためのメソッドである。入力した文字列を画面に返さないように設定している。

 下の方にLineReaderというReaderクラスを継承した packge privateな クラスが定義されている。このクラスは最後尾にあるstatic initializerの中でインスタンスが作成されている。

/*
 * Copyright (c) 2005, 2018, 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;
import java.util.*;
import java.nio.charset.Charset;
import jdk.internal.access.JavaIOAccess;
import jdk.internal.access.SharedSecrets;
import sun.nio.cs.StreamDecoder;
import sun.nio.cs.StreamEncoder;
public final class Console implements Flushable
{
    public PrintWriter writer() {
        return pw;
    }
    public Reader reader() {
        return reader;
    }
    public Console format(String fmt, Object …args) {
        formatter.format(fmt, args).flush();
        return this;
    }
    public Console printf(String format, Object … args) {
        return format(format, args);
    }
    public String readLine(String fmt, Object … args) {
        String line = null;
        synchronized (writeLock) {
            synchronized(readLock) {
                if (!fmt.isEmpty())
                    pw.format(fmt, args);
                try {
                    char[] ca = readline(false);
                    if (ca != null)
                        line = new String(ca);
                } catch (IOException x) {
                    throw new IOError(x);
                }
            }
        }
        return line;
    }
    public String readLine() {
        return readLine("");
    }
    public char[] readPassword(String fmt, Object … args) {
        char[] passwd = null;
        synchronized (writeLock) {
            synchronized(readLock) {
                installShutdownHook();
                try {
                    restoreEcho = echo(false);
                } catch (IOException x) {
                    throw new IOError(x);
                }
                IOError ioe = null;
                try {
                    if (!fmt.isEmpty())
                        pw.format(fmt, args);
                    passwd = readline(true);
                } catch (IOException x) {
                    ioe = new IOError(x);
                } finally {
                    try {
                        if (restoreEcho)
                            restoreEcho = echo(true);
                    } catch (IOException x) {
                        if (ioe == null)
                            ioe = new IOError(x);
                        else
                            ioe.addSuppressed(x);
                    }
                    if (ioe != null)
                        throw ioe;
                }
                pw.println();
            }
        }
        return passwd;
    }
    private void installShutdownHook() {
        if (shutdownHookInstalled)
            return;
        try {
            // Add a shutdown hook to restore console's echo state should
            // it be necessary.
            SharedSecrets.getJavaLangAccess()
                .registerShutdownHook(0 /* shutdown hook invocation order */,
                    false /* only register if shutdown is not in progress */,
                    new Runnable() {
                        public void run() {
                            try {
                                if (restoreEcho) {
                                    echo(true);
                                }
                            } catch (IOException x) { }
                        }
                    });
        } catch (IllegalStateException e) {
            // shutdown is already in progress and readPassword is first used
            // by a shutdown hook
        }
        shutdownHookInstalled = true;
    }
    public char[] readPassword() {
        return readPassword("");
    }
    public void flush() {
        pw.flush();
    }
    private Object readLock;
    private Object writeLock;
    private Reader reader;
    private Writer out;
    private PrintWriter pw;
    private Formatter formatter;
    private Charset cs;
    private char[] rcb;
    private boolean restoreEcho;
    private boolean shutdownHookInstalled;
    private static native String encoding();
    /*
     * Sets the console echo status to {@code on} and returns the previous
     * console on/off status.
     * @param on    the echo status to set to. {@code true} for echo on and
     *              {@code false} for echo off
     * @return true if the previous console echo status is on
     */
    private static native boolean echo(boolean on) throws IOException;
    private char[] readline(boolean zeroOut) throws IOException {
        int len = reader.read(rcb, 0, rcb.length);
        if (len < 0)
            return null;  //EOL
        if (rcb[len-1] == '\r')
            len–;        //remove CR at end;
        else if (rcb[len-1] == '\n') {
            len–;        //remove LF at end;
            if (len > 0 && rcb[len-1] == '\r')
                len–;    //remove the CR, if there is one
        }
        char[] b = new char[len];
        if (len > 0) {
            System.arraycopy(rcb, 0, b, 0, len);
            if (zeroOut) {
                Arrays.fill(rcb, 0, len, ' ');
            }
        }
        return b;
    }
    private char[] grow() {
        assert Thread.holdsLock(readLock);
        char[] t = new char[rcb.length * 2];
        System.arraycopy(rcb, 0, t, 0, rcb.length);
        rcb = t;
        return rcb;
    }
    class LineReader extends Reader {
        private Reader in;
        private char[] cb;
        private int nChars, nextChar;
        boolean leftoverLF;
        LineReader(Reader in) {
            this.in = in;
            cb = new char[1024];
            nextChar = nChars = 0;
            leftoverLF = false;
        }
        public void close () {}
        public boolean ready() throws IOException {
            //in.ready synchronizes on readLock already
            return in.ready();
        }
        public int read(char cbuf[], int offset, int length)
            throws IOException
        {
            int off = offset;
            int end = offset + length;
            if (offset < 0 || offset > cbuf.length || length < 0 ||
                end < 0 || end > cbuf.length) {
                throw new IndexOutOfBoundsException();
            }
            synchronized(readLock) {
                boolean eof = false;
                char c = 0;
                for (;;) {
                    if (nextChar >= nChars) {   //fill
                        int n = 0;
                        do {
                            n = in.read(cb, 0, cb.length);
                        } while (n == 0);
                        if (n > 0) {
                            nChars = n;
                            nextChar = 0;
                            if (n < cb.length &&
                                cb[n-1] != '\n' && cb[n-1] != '\r') {
                                /*
                                 * we're in canonical mode so each "fill" should
                                 * come back with an eol. if there no lf or nl at
                                 * the end of returned bytes we reached an eof.
                                 */
                                eof = true;
                            }
                        } else { /*EOF*/
                            if (off – offset == 0)
                                return -1;
                            return off – offset;
                        }
                    }
                    if (leftoverLF && cbuf == rcb && cb[nextChar] == '\n') {
                        /*
                         * if invoked by our readline, skip the leftover, otherwise
                         * return the LF.
                         */
                        nextChar++;
                    }
                    leftoverLF = false;
                    while (nextChar < nChars) {
                        c = cbuf[off++] = cb[nextChar];
                        cb[nextChar++] = 0;
                        if (c == '\n') {
                            return off – offset;
                        } else if (c == '\r') {
                            if (off == end) {
                                /* no space left even the next is LF, so return
                                 * whatever we have if the invoker is not our
                                 * readLine()
                                 */
                                if (cbuf == rcb) {
                                    cbuf = grow();
                                    end = cbuf.length;
                                } else {
                                    leftoverLF = true;
                                    return off – offset;
                                }
                            }
                            if (nextChar == nChars && in.ready()) {
                                /*
                                 * we have a CR and we reached the end of
                                 * the read in buffer, fill to make sure we
                                 * don't miss a LF, if there is one, it's possible
                                 * that it got cut off during last round reading
                                 * simply because the read in buffer was full.
                                 */
                                nChars = in.read(cb, 0, cb.length);
                                nextChar = 0;
                            }
                            if (nextChar < nChars && cb[nextChar] == '\n') {
                                cbuf[off++] = '\n';
                                nextChar++;
                            }
                            return off – offset;
                        } else if (off == end) {
                           if (cbuf == rcb) {
                                cbuf = grow();
                                end = cbuf.length;
                           } else {
                               return off – offset;
                           }
                        }
                    }
                    if (eof)
                        return off – offset;
                }
            }
        }
    }
    // Set up JavaIOAccess in SharedSecrets
    static {
        SharedSecrets.setJavaIOAccess(new JavaIOAccess() {
            public Console console() {
                if (istty()) {
                    if (cons == null)
                        cons = new Console();
                    return cons;
                }
                return null;
            }
            public Charset charset() {
                // This method is called in sun.security.util.Password,
                // cons already exists when this method is called
                return cons.cs;
            }
        });
    }
    private static Console cons;
    private static native boolean istty();
    private Console() {
        readLock = new Object();
        writeLock = new Object();
        String csname = encoding();
        if (csname != null) {
            try {
                cs = Charset.forName(csname);
            } catch (Exception x) {}
        }
        if (cs == null)
            cs = Charset.defaultCharset();
        out = StreamEncoder.forOutputStreamWriter(
                  new FileOutputStream(FileDescriptor.out),
                  writeLock,
                  cs);
        pw = new PrintWriter(out, true) { public void close() {} };
        formatter = new Formatter(out);
        reader = new LineReader(StreamDecoder.forInputStreamReader(
                     new FileInputStream(FileDescriptor.in),
                     readLock,
                     cs));
        rcb = new char[1024];
    }
}
JDK

java.io.ByteArrayOutputStreamクラス

ByteArrayOutputStreamクラスはbyte配列のストリームへ書きこむ出力ストリームで,OutputStreamクラスを継承して実装されている。バッファとしてbyte[]型のインスタンス変数buf,そして,バッファに書き込まれたサイズを示すint型のインスタンス変数countが宣言されている。

 コンストラクタはByteArrayOutputStream()と,バッファサイズを指定するByteArrayOutputStream(int size)が実装されている。ディフォルトのバッファサイズは32である。バッファサイズが不足すると,grow(int minCapacity)メソッドでバッファを拡張する。新しいバッファサイズはint newCapacity = oldCapacity << 1という式で算出されているので,1bitの左シフト,すなわち,2倍である。

 書き込むためのメソッドとしては,write(int b),write(byte b[], int off, int len),writeBytes(byte b[])が実装されている。

write(int b) メソッドは引数のint値をbyte型にキャストして書き込む。 write(byte b[], int off, int len) メソッドは引数で渡されたbyte[]型の配列を指定のオフセットから指定の長さだけ書き込む。このメソッド内部はSystem.arraycopyメソッドを用いて配列をコピーしている。writeBytes(byte b[])メソッドは引数で与えられたbyte[]型の配列を先頭からすべて書き込むようにwrite()メソッドを呼び出している。

writeTo(OutputStream out)メソッドでは,引数で与えられたOutputStreamに対して,バッファの内容を書き出す。 toByteArray()メソッドではバッファの内容をbyte[]型配列として返す。

size()メソッドでは,バッファ内に書き込まれているサイズを返す。また,toString()メソッドではバッファ内のbyte[]配列からStringのインスタンスを作成して返す。toString(String charsetName)メソッドでは,指定の文字セットを使ってバッファ内のbyte[]配列をStringに変換して返す。

/*
 * Copyright (c) 1994, 2018, 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;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Objects;
public class ByteArrayOutputStream extends OutputStream {
    protected byte buf[];
    protected int count;
    public ByteArrayOutputStream() {
        this(32);
    }
    public ByteArrayOutputStream(int size) {
        if (size < 0) {
            throw new IllegalArgumentException("Negative initial size: "
                                               + size);
        }
        buf = new byte[size];
    }
    private void ensureCapacity(int minCapacity) {
        // overflow-conscious code
        if (minCapacity – buf.length > 0)
            grow(minCapacity);
    }
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE – 8;
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = buf.length;
        int newCapacity = oldCapacity << 1;
        if (newCapacity – minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity – MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        buf = Arrays.copyOf(buf, newCapacity);
    }
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
    public synchronized void write(int b) {
        ensureCapacity(count + 1);
        buf[count] = (byte) b;
        count += 1;
    }
    public synchronized void write(byte b[], int off, int len) {
        Objects.checkFromIndexSize(off, len, b.length);
        ensureCapacity(count + len);
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }
    public void writeBytes(byte b[]) {
        write(b, 0, b.length);
    }
    public synchronized void writeTo(OutputStream out) throws IOException {
        out.write(buf, 0, count);
    }
    public synchronized void reset() {
        count = 0;
    }
    public synchronized byte[] toByteArray() {
        return Arrays.copyOf(buf, count);
    }
    public synchronized int size() {
        return count;
    }
    public synchronized String toString() {
        return new String(buf, 0, count);
    }
    public synchronized String toString(String charsetName)
        throws UnsupportedEncodingException
    {
        return new String(buf, 0, count, charsetName);
    }
    public synchronized String toString(Charset charset) {
        return new String(buf, 0, count, charset);
    }
    @Deprecated
    public synchronized String toString(int hibyte) {
        return new String(buf, hibyte, 0, count);
    }
    public void close() throws IOException {
    }
}
JDK

java.io.ByteArrayInputStreamクラス

ByteArrayInputStreamはInputStreamからバイト配列としてデータを読み込むためのクラスである。byte型の配列としてbufというインスタンス変数が,次の読込位置を示すint型のインスタンス変数posが定義されている。

コンストラクタは,以下のようなものが定義されている。一つ目のものは与えられたバイト配列をすべて読み込む。2つ目のコンストラクタは与えられたバイト配列のうち,指定されたオフセットから指定された長さだけを読み込む。

  • ByteArrayInputStream(byte buf[])
  • ByteArrayInputStream(byte buf[], int offset, int length)

int read()メソッドは次のバイトを読込み,int型で返す。実装は0xFFとの積を計算している。int read(byte b[], int off, int len)メソッドでは引数で与えられたbyte型配列b[]に読み込んだデータをSystem.arraycopy()メソッドを使ってコピーしている。

readAllBytes()メソッドはストリームからすべてのデータをbyte型配列へ読み込んで返す。readNBytes(byte[] b, int off, int len)メソッドは指定のオフセットから指定の長さだけbyte型配列に読み込む。skip(long n)メソッドは,指定した長さだけストリームをスキップする。available()メソッドは残りのバイト数を返す。メソッド名と戻り値の内容にややずれがある印象だ。close()メソッドは実装されているものの,空である。

/*
 * Copyright (c) 1994, 2018, 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;
import java.util.Arrays;
import java.util.Objects;
public class ByteArrayInputStream extends InputStream {
    protected byte buf[];
    protected int pos;
    protected int mark = 0;
    protected int count;
    public ByteArrayInputStream(byte buf[]) {
        this.buf = buf;
        this.pos = 0;
        this.count = buf.length;
    }
    public ByteArrayInputStream(byte buf[], int offset, int length) {
        this.buf = buf;
        this.pos = offset;
        this.count = Math.min(offset + length, buf.length);
        this.mark = offset;
    }
    public synchronized int read() {
        return (pos < count) ? (buf[pos++] & 0xff) : -1;
    }
    public synchronized int read(byte b[], int off, int len) {
        Objects.checkFromIndexSize(off, len, b.length);
        if (pos >= count) {
            return -1;
        }
        int avail = count – pos;
        if (len > avail) {
            len = avail;
        }
        if (len <= 0) {
            return 0;
        }
        System.arraycopy(buf, pos, b, off, len);
        pos += len;
        return len;
    }
    public synchronized byte[] readAllBytes() {
        byte[] result = Arrays.copyOfRange(buf, pos, count);
        pos = count;
        return result;
    }
    public int readNBytes(byte[] b, int off, int len) {
        int n = read(b, off, len);
        return n == -1 ? 0 : n;
    }
    public synchronized long transferTo(OutputStream out) throws IOException {
        int len = count – pos;
        out.write(buf, pos, len);
        pos = count;
        return len;
    }
    public synchronized long skip(long n) {
        long k = count – pos;
        if (n < k) {
            k = n < 0 ? 0 : n;
        }
        pos += k;
        return k;
    }
    public synchronized int available() {
        return count – pos;
    }
    public boolean markSupported() {
        return true;
    }
    public void mark(int readAheadLimit) {
        mark = pos;
    }
    public synchronized void reset() {
        pos = mark;
    }
    public void close() throws IOException {
    }
}