common-ioのByteArrayOutputStream読み
まず、その中のインスタンス変数を分析します.buffers:buffer倉庫と見なすことができます.中にはすでに読み込まれたすべてのデータcurrentBufferIndexが入っています.使用中のbufferのindexcountです.buffersの中のすべてのバイト数currentBufferを保存するために使用されます.現在の使用bufferです.これは理解しやすいです.FilledBufferSum:これは最初は特に理解していませんでしたが、後で理解しました.主にすべての満bufferのバイト数の合計を保存しました.例を挙げると、最初のbufferのサイズは32で、filledBufferSumは0で、countは0で、それから私たちは現在のbufferに5バイトのデータを入れて、今countは5で、次の私たちのcount-filedBufferSumは私たちが次に保存したbufferのポインタで、例えば私たちが25バイトを置くと、今countは30になります.FilledBufferSumは依然として0で、私たちは更に3バイトを入れて、今countは33になって、bufferの初期の大きさより大きくなって、拡張して、新しいbufferを作って、古いbufferをbuffersの中に置いて、それからfilledBufferSumは32になって、拡張した後の残りの1バイトを新しい申請のbufferの中に置いて、次は私たちが更に10バイトのデータを入れたいと思って、countは33で、filedBufferSumは32で、私たちが保存したポインタは1であるべきです.0バイトは前回の拡張後の残りのバイト数を保存したからです.1.まずコンストラクション関数を見てみましょう.
一つはパラメータがないときに1024のサイズのbufferを作成し、一つはユーザーが入力したサイズに基づいてbufferを作成することです.これはよく理解できます.肝心なのはneedNewBuffer関数で、これは以下に説明します.2.needNewBuffer関数を見てみましょう.これはこの類の魂です.
まず、期間を理解するために、elseブランチについてお話しします.ifブランチはreset関数で説明します.
これが私たちの伝統的な意味で新しいbufferを作成します.この中にcurrentBufferがnullなら、
1つを初期化します.このブランチは作成時にこのブランチを歩き、次のブランチは現在のbufferを
のlengthに2を乗じて必要なサイズと比較して最大値を取って新しいbufferのサイズとし、
次に、filledBufferSumの値を変更します.次のコードは本当にbufferを作成する場所です.
彼をbuffersに追加します
3.次にwrite関数を見てみましょう
public void write(byte[] b, int off, int len) {
まずいくつかの検査で、配列の境界を越えて、これらの判断は親の中の判断と同じです.次は本当に書く操作を実現します.まず新しいcountを計算し、書くバイト数を初期のremainingとして計算し、今回書くポインタの位置を計算します.前回の総サイズから、すでにいっぱい保存されているbufferの中のバイト数を減算します.ここでremainingと現在残っている空間を比較し,最小値をとる.そして配列コピー動作をします.そして完全に書き終わったかどうかを判断し、書き終わっていなければスペースを割り当て、最後にスペースを割り当てる動作を実行し、最後にbufferにループして書き込む.4.次に、write関数を理解するために強化します.
以上のことを理解すれば,この関数は特に理解しやすく,まず今回書き込むべきポインタの位置を求め,空間がないことを発見したら新しい空間を割り当て,bufferにデータを書き,書き込むデータの総数を加算する.
5.write関数の研究
この関数は、主に書き込むべきポインタの位置を計算し、InputStreamからcurrentBuffer、inBufferPosから最大残りの長さバイトを合計し、-1でなければ現在のポインタとreadCountを変化させ、現在のポインタとcurrentBufferのlengthが等しい場合、バッファを拡張し、読み終わるまでループします.
6.reset関数
私は最初は理解していなかったが、今は理解した.たとえば、最初のファイルに書き込みを行い、バッファは
リリース、私たちは次のファイルを読む必要があります.では、私たちは今、空間を申請することはできません.前回のバッファに対して
多重化、ここではまずいくつかの状態変数を0にクリアし、次に現在のbufferを0番目のbufferに設定します.
前回割り当てたbufferを使うことができます.問題をはっきり言うために、もう一度見てみましょう.
この関数を呼び出すとcurrentBufferIndexは0で、buffersに他のバッファがあれば
現在のbufferIndexに1を追加し、次のバッファに戻ると、より効率的に感じられます.ここでは、徹底的に
この中の流れを理解しました.
7.次にwriteTo関数の実装を見てみましょう
この関数は主にbufのデータをユーザが指定したOutputStreamに直接書き込むことを実現している.この中とJDKの中の実現の唯一の違いは、ここでbuffersのデータが指定されたOutputStreamにすべて書き込まれるようにループすることです.
8.次にtoByteArrayの実装について説明します.
public synchronized byte[] toByteArray() {
この関数はよく理解されています.countサイズのbyte配列を作成し、buffersをループして、各バッファのデータを返すバイト配列にcopyします.
次の完全なプログラム:
public ByteArrayOutputStream() {
this(1024);
}
public ByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException(
"Negative initial size: " + size);
}
needNewBuffer(size);
}
一つはパラメータがないときに1024のサイズのbufferを作成し、一つはユーザーが入力したサイズに基づいてbufferを作成することです.これはよく理解できます.肝心なのはneedNewBuffer関数で、これは以下に説明します.2.needNewBuffer関数を見てみましょう.これはこの類の魂です.
private void needNewBuffer(int newcount) {
if (currentBufferIndex < buffers.size() - 1) {
//Recycling old buffer
filledBufferSum += currentBuffer.length;
currentBufferIndex++;
currentBuffer = getBuffer(currentBufferIndex);
} else {
//Creating new buffer
int newBufferSize;
if (currentBuffer == null) {
newBufferSize = newcount;
filledBufferSum = 0;
} else {
newBufferSize = Math.max(
currentBuffer.length << 1,
newcount - filledBufferSum);
filledBufferSum += currentBuffer.length;
}
currentBufferIndex++;
currentBuffer = new byte[newBufferSize];
buffers.add(currentBuffer);
}
}
まず、期間を理解するために、elseブランチについてお話しします.ifブランチはreset関数で説明します.
これが私たちの伝統的な意味で新しいbufferを作成します.この中にcurrentBufferがnullなら、
1つを初期化します.このブランチは作成時にこのブランチを歩き、次のブランチは現在のbufferを
のlengthに2を乗じて必要なサイズと比較して最大値を取って新しいbufferのサイズとし、
次に、filledBufferSumの値を変更します.次のコードは本当にbufferを作成する場所です.
彼をbuffersに追加します
3.次にwrite関数を見てみましょう
public void write(byte[] b, int off, int len) {
if ((off < 0)
|| (off > b.length)
|| (len < 0)
|| ((off + len) > b.length)
|| ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
synchronized (this) {
int newcount = count + len;
int remaining = len;
int inBufferPos = count - filledBufferSum;
while (remaining > 0) {
int part = Math.min(remaining, currentBuffer.length - inBufferPos);
System.arraycopy(b, off + len - remaining, currentBuffer, inBufferPos, part);
remaining -= part;
if (remaining > 0) {
needNewBuffer(newcount);
inBufferPos = 0;
}
}
count = newcount;
}
}
まずいくつかの検査で、配列の境界を越えて、これらの判断は親の中の判断と同じです.次は本当に書く操作を実現します.まず新しいcountを計算し、書くバイト数を初期のremainingとして計算し、今回書くポインタの位置を計算します.前回の総サイズから、すでにいっぱい保存されているbufferの中のバイト数を減算します.ここでremainingと現在残っている空間を比較し,最小値をとる.そして配列コピー動作をします.そして完全に書き終わったかどうかを判断し、書き終わっていなければスペースを割り当て、最後にスペースを割り当てる動作を実行し、最後にbufferにループして書き込む.4.次に、write関数を理解するために強化します.
/**
* Write a byte to byte array.
* @param b the byte to write
*/
public synchronized void write(int b) {
int inBufferPos = count - filledBufferSum;
if (inBufferPos == currentBuffer.length) {
needNewBuffer(count + 1);
inBufferPos = 0;
}
currentBuffer[inBufferPos] = (byte) b;
count++;
}
以上のことを理解すれば,この関数は特に理解しやすく,まず今回書き込むべきポインタの位置を求め,空間がないことを発見したら新しい空間を割り当て,bufferにデータを書き,書き込むデータの総数を加算する.
5.write関数の研究
public synchronized int write(InputStream in) throws IOException {
int readCount = 0;
int inBufferPos = count - filledBufferSum;
int n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos);
while (n != -1) {
readCount += n;
inBufferPos += n;
count += n;
if (inBufferPos == currentBuffer.length) {
needNewBuffer(currentBuffer.length);
inBufferPos = 0;
}
n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos);
}
return readCount;
}
この関数は、主に書き込むべきポインタの位置を計算し、InputStreamからcurrentBuffer、inBufferPosから最大残りの長さバイトを合計し、-1でなければ現在のポインタとreadCountを変化させ、現在のポインタとcurrentBufferのlengthが等しい場合、バッファを拡張し、読み終わるまでループします.
6.reset関数
public synchronized void reset() {
count = 0;
filledBufferSum = 0;
currentBufferIndex = 0;
currentBuffer = getBuffer(currentBufferIndex);
}
私は最初は理解していなかったが、今は理解した.たとえば、最初のファイルに書き込みを行い、バッファは
リリース、私たちは次のファイルを読む必要があります.では、私たちは今、空間を申請することはできません.前回のバッファに対して
多重化、ここではまずいくつかの状態変数を0にクリアし、次に現在のbufferを0番目のbufferに設定します.
前回割り当てたbufferを使うことができます.問題をはっきり言うために、もう一度見てみましょう.
needNewBuffer if ,
if (currentBufferIndex < buffers.size() - 1) {
//Recycling old buffer
filledBufferSum += currentBuffer.length;
currentBufferIndex++;
currentBuffer = getBuffer(currentBufferIndex);
この関数を呼び出すとcurrentBufferIndexは0で、buffersに他のバッファがあれば
現在のbufferIndexに1を追加し、次のバッファに戻ると、より効率的に感じられます.ここでは、徹底的に
この中の流れを理解しました.
7.次にwriteTo関数の実装を見てみましょう
public synchronized void writeTo(OutputStream out) throws IOException {
int remaining = count;
for (int i = 0; i < buffers.size(); i++) {
byte[] buf = getBuffer(i);
int c = Math.min(buf.length, remaining);
out.write(buf, 0, c);
remaining -= c;
if (remaining == 0) {
break;
}
}
}
この関数は主にbufのデータをユーザが指定したOutputStreamに直接書き込むことを実現している.この中とJDKの中の実現の唯一の違いは、ここでbuffersのデータが指定されたOutputStreamにすべて書き込まれるようにループすることです.
8.次にtoByteArrayの実装について説明します.
public synchronized byte[] toByteArray() {
int remaining = count;
if (remaining == 0) {
return EMPTY_BYTE_ARRAY;
}
byte newbuf[] = new byte[remaining];
int pos = 0;
for (int i = 0; i < buffers.size(); i++) {
byte[] buf = getBuffer(i);
int c = Math.min(buf.length, remaining);
System.arraycopy(buf, 0, newbuf, pos, c);
pos += c;
remaining -= c;
if (remaining == 0) {
break;
}
}
return newbuf;
}
この関数はよく理解されています.countサイズのbyte配列を作成し、buffersをループして、各バッファのデータを返すバイト配列にcopyします.
次の完全なプログラム:
public class ByteArrayOutputStream extends OutputStream {
/** A singleton empty byte array. */
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
/** The list of buffers, which grows and never reduces. */
private final List<byte[]> buffers = new ArrayList<byte[]>();
/** The index of the current buffer. */
private int currentBufferIndex;
/** The total count of bytes in all the filled buffers. */
private int filledBufferSum;
/** The current buffer. */
private byte[] currentBuffer;
/** The total count of bytes written. */
private int count;
/**
* Creates a new byte array output stream. The buffer capacity is
* initially 1024 bytes, though its size increases if necessary.
*/
public ByteArrayOutputStream() {
this(1024);
}
/**
* Creates a new byte array output stream, with a buffer capacity of
* the specified size, in bytes.
*
* @param size the initial size
* @throws IllegalArgumentException if size is negative
*/
public ByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException(
"Negative initial size: " + size);
}
needNewBuffer(size);
}
/**
* Makes a new buffer available either by allocating
* a new one or re-cycling an existing one.
*
* @param newcount the size of the buffer if one is created
*/
private void needNewBuffer(int newcount) {
if (currentBufferIndex < buffers.size() - 1) {
//Recycling old buffer
filledBufferSum += currentBuffer.length;
currentBufferIndex++;
currentBuffer = buffers.get(currentBufferIndex);
} else {
//Creating new buffer
int newBufferSize;
if (currentBuffer == null) {
newBufferSize = newcount;
filledBufferSum = 0;
} else {
newBufferSize = Math.max(
currentBuffer.length << 1,
newcount - filledBufferSum);
filledBufferSum += currentBuffer.length;
}
currentBufferIndex++;
currentBuffer = new byte[newBufferSize];
buffers.add(currentBuffer);
}
}
/**
* Write the bytes to byte array.
* @param b the bytes to write
* @param off The start offset
* @param len The number of bytes to write
*/
@Override
public void write(byte[] b, int off, int len) {
if ((off < 0)
|| (off > b.length)
|| (len < 0)
|| ((off + len) > b.length)
|| ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
synchronized (this) {
int newcount = count + len;
int remaining = len;
int inBufferPos = count - filledBufferSum;
while (remaining > 0) {
int part = Math.min(remaining, currentBuffer.length - inBufferPos);
System.arraycopy(b, off + len - remaining, currentBuffer, inBufferPos, part);
remaining -= part;
if (remaining > 0) {
needNewBuffer(newcount);
inBufferPos = 0;
}
}
count = newcount;
}
}
/**
* Write a byte to byte array.
* @param b the byte to write
*/
@Override
public synchronized void write(int b) {
int inBufferPos = count - filledBufferSum;
if (inBufferPos == currentBuffer.length) {
needNewBuffer(count + 1);
inBufferPos = 0;
}
currentBuffer[inBufferPos] = (byte) b;
count++;
}
/**
* Writes the entire contents of the specified input stream to this
* byte stream. Bytes from the input stream are read directly into the
* internal buffers of this streams.
*
* @param in the input stream to read from
* @return total number of bytes read from the input stream
* (and written to this stream)
* @throws IOException if an I/O error occurs while reading the input stream
* @since Commons IO 1.4
*/
public synchronized int write(InputStream in) throws IOException {
int readCount = 0;
int inBufferPos = count - filledBufferSum;
int n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos);
while (n != -1) {
readCount += n;
inBufferPos += n;
count += n;
if (inBufferPos == currentBuffer.length) {
needNewBuffer(currentBuffer.length);
inBufferPos = 0;
}
n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos);
}
return readCount;
}
/**
* Return the current size of the byte array.
* @return the current size of the byte array
*/
public synchronized int size() {
return count;
}
/**
* Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an <tt>IOException</tt>.
*
* @throws IOException never (this method should not declare this exception
* but it has to now due to backwards compatability)
*/
@Override
public void close() throws IOException {
//nop
}
/**
* @see java.io.ByteArrayOutputStream#reset()
*/
public synchronized void reset() {
count = 0;
filledBufferSum = 0;
currentBufferIndex = 0;
currentBuffer = buffers.get(currentBufferIndex);
}
/**
* Writes the entire contents of this byte stream to the
* specified output stream.
*
* @param out the output stream to write to
* @throws IOException if an I/O error occurs, such as if the stream is closed
* @see java.io.ByteArrayOutputStream#writeTo(OutputStream)
*/
public synchronized void writeTo(OutputStream out) throws IOException {
int remaining = count;
for (byte[] buf : buffers) {
int c = Math.min(buf.length, remaining);
out.write(buf, 0, c);
remaining -= c;
if (remaining == 0) {
break;
}
}
}
/**
* Fetches entire contents of an <code>InputStream</code> and represent
* same data as result InputStream.
* <p>
* This method is useful where,
* <ul>
* <li>Source InputStream is slow.</li>
* <li>It has network resources associated, so we cannot keep it open for
* long time.</li>
* <li>It has network timeout associated.</li>
* </ul>
* It can be used in favor of {@link #toByteArray()}, since it
* avoids unnecessary allocation and copy of byte[].<br>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>.
*
* @param input Stream to be fully buffered.
* @return A fully buffered stream.
* @throws IOException if an I/O error occurs
*/
public static InputStream toBufferedInputStream(InputStream input)
throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
output.write(input);
return output.toBufferedInputStream();
}
/**
* Gets the current contents of this byte stream as a Input Stream. The
* returned stream is backed by buffers of <code>this</code> stream,
* avoiding memory allocation and copy, thus saving space and time.<br>
*
* @return the current contents of this output stream.
* @see java.io.ByteArrayOutputStream#toByteArray()
* @see #reset()
* @since Commons IO 2.0
*/
private InputStream toBufferedInputStream() {
int remaining = count;
if (remaining == 0) {
return new ClosedInputStream();
}
List<ByteArrayInputStream> list = new ArrayList<ByteArrayInputStream>(buffers.size());
for (byte[] buf : buffers) {
int c = Math.min(buf.length, remaining);
list.add(new ByteArrayInputStream(buf, 0, c));
remaining -= c;
if (remaining == 0) {
break;
}
}
return new SequenceInputStream(Collections.enumeration(list));
}
/**
* Gets the curent contents of this byte stream as a byte array.
* The result is independent of this stream.
*
* @return the current contents of this output stream, as a byte array
* @see java.io.ByteArrayOutputStream#toByteArray()
*/
public synchronized byte[] toByteArray() {
int remaining = count;
if (remaining == 0) {
return EMPTY_BYTE_ARRAY;
}
byte newbuf[] = new byte[remaining];
int pos = 0;
for (byte[] buf : buffers) {
int c = Math.min(buf.length, remaining);
System.arraycopy(buf, 0, newbuf, pos, c);
pos += c;
remaining -= c;
if (remaining == 0) {
break;
}
}
return newbuf;
}
/**
* Gets the curent contents of this byte stream as a string.
* @return the contents of the byte array as a String
* @see java.io.ByteArrayOutputStream#toString()
*/
@Override
public String toString() {
return new String(toByteArray());
}
/**
* Gets the curent contents of this byte stream as a string
* using the specified encoding.
*
* @param enc the name of the character encoding
* @return the string converted from the byte array
* @throws UnsupportedEncodingException if the encoding is not supported
* @see java.io.ByteArrayOutputStream#toString(String)
*/
public String toString(String enc) throws UnsupportedEncodingException {
return new String(toByteArray(), enc);
}
}