Java IO 过滤流 BufferedInput/OutputStream
@author ixenos
概念
BufferedInput/OutputStream是实现缓存的过滤流,他们分别是FilterInput/OutputStream的子类。
BufferedInputStream工作流程
stream-->buf--read buf-->I
1.当一个BufferedInputStream被创建时,一个内部的缓冲区 byte[] buf = new byte[size] 也被建立,size默认是8192也就是默认创建一个8kb大小的缓存空间,
工作时由内部方法fill()预先在缓冲区存储来自连接输入流的数据;最终的数据来源由底层流决定,比如new FileInputStream("a.txt")来源就是a.txt,而我们过滤流的数据来源是节点流!
private static int DEFAULT_BUFFER_SIZE = 8192; //默认缓冲数组长度大小,折合单位有8kb
protected volatile byte buf[]; //底层维护的缓冲数组变量 public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE); //默认8192
} public BufferedInputStream(InputStream in, int size) {
super(in); //引用基类FilterInputStream的构造方法,基类有底层流变量
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size]; //初始化缓冲数组,指定大小为size
}
2.当BufferedInputStream的read方法被调用时,数据将从缓冲区中移出,而不是底层的输入流;
3.当BufferedInputStream缓冲区数据用完时,他自动从底层输入流中补充数据。
read()源码分析:
//返回下一个数据字节,如果到达流末尾则返回-1,数据流向返回值!
1 public synchronized int read() throws IOException {
if (pos >= count) { //当缓存指针等于或者超过count时,说明buf已满
fill(); //fill()从节点流中读取数据存放到buf缓冲区
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff; //得到非空buf缓冲当前索引为pos位置的一字节数据,pos++ 缓冲区指针移动一位
} //getBufIfOpen对buf进行非空判断
private byte[] getBufIfOpen() throws IOException {
byte[] buffer = buf; //用一个引用变量引用buf
if (buffer == null)
throw new IOException("Stream closed");
return buffer; //返回buffer,实质上指向buf
}
read(byte[], int, int)源码分析 :
//pos是起始/下一次读取buffer的位置,
//markpos是最新一次已读取的位置,
//count是缓冲数组被填充的大小-1(因为是作为index存在的,从0开始)
//len是b要读取的最大字节数
//返回读取的字节数,如果流到达末尾返回-1,数据流向b数组!
public synchronized int read(byte b[], int off, int len)
throws IOException
{ /*这里只做检查,流关闭则提前抛出,以避免拖到fill()中的getBufIfOpen()再抛出的情况
private byte[] getBufIfOpen() throws IOException {
byte[] buffer = buf; //引用传递,指向当前buf变量指向的内存
if (buffer == null) //就为了这个非空判断而已
throw new IOException("Stream closed");
return buffer; //这里返回值是没人接收的,方法结束抛弃局部变量buffer,不对buf造成影响
}
*/
getBufIfOpen(); // Check for closed stream 关闭流将抛出异常
//指定数组的越界判断
if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
} int n = 0;
//循环写数据到b,直到buffer数据不足返回-1,此时nread已累加记录
for (;;) {
int nread = read1(b, off + n, len - n);//读缓冲区数据到b
if (nread <= 0)
return (n == 0) ? nread : n;
n += nread;
//读完指定长度时返回
if (n >= len)
return n;
// if not closed but no bytes available, return
//没读完指定长度,但缓冲区没数据时返回当前n
InputStream input = in;
if (input != null && input.available() <= 0)
return n;
}
} /**
* read1方法是该read底层用来读取缓冲区buf的数据进指定数组的方法
* 而fill方法又是read1方法中用来读取底层字节流到缓冲区buf的方法
* 读取数据写进指定数组的一部分,必要时每次从底层流尽量读取数据
*/
private int read1(byte[] b, int off, int len) throws IOException {
int avail = count - pos; //开始时为0
if (avail <= 0) {
/* 如果所请求的长度大于等于缓冲区,并且还没读取过buf
50 (即刚开始使用时,扩充缓冲区成本不值得,回归底层流),
就没必要用缓冲区了,将直接从底层流读取数据。
*/
if (len >= getBufIfOpen().length && markpos < 0) {
//直接调用底层流的read方法,写进指定的内存b
return getInIfOpen().read(b, off, len);
}
//请求fill()方法来读取底层流数据(多次使用后如果长度大于缓冲区,为了数据保护,将扩充缓冲区)
fill();
avail = count - pos; //avail是
if (avail <= 0) return -1;
}
int cnt = (avail < len) ? avail : len; //cnt是要写入b的字节数,如果b中剩余字节数avail比要刷入的数据长度len大,则cnt为len
System.arraycopy(getBufIfOpen(), pos, b, off, cnt); //复制指定范围非空buf数据到b
pos += cnt;
return cnt;
} //fill()方法填充空间,是底层用来读取流数据到缓冲区buf
/**
* Fills the buffer with more data, taking into account
* shuffling and other tricks for dealing with marks.
* Assumes that it is being called by a synchronized method.
* This method also assumes that all data has already been read in,
* hence pos > count.
*/
private void fill() throws IOException {
byte[] buffer = getBufIfOpen();
//pos是起始/下一次读取buffer的位置,markpos是最新一次已读取的位置,count是缓冲数组被填充的大小-1(因为是作为index存在的,从0开始)
//起始小于零表明没有pos移动,从源码可知
if (markpos < 0)
pos = 0; /* no mark: throw away the buffer */
//当pos比buffer更长时,即
else if (pos >= buffer.length) /* no room left in buffer */
//markpos也有前移时,数组自我复制丢弃早期部分
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
pos = sz;
markpos = 0;
//buffer大小超过理论规模时,重置,通过改变pos“丢弃”缓冲区内容
} else if (buffer.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
//buffer大小超过本地VM内存限制:MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8
} else if (buffer.length >= MAX_BUFFER_SIZE) {
throw new OutOfMemoryError("Required array size too large");
} else { /* grow buffer */ //没有顾忌时,扩充缓冲区大小
int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
pos * 2 : MAX_BUFFER_SIZE;
if (nsz > marklimit)
nsz = marklimit;
byte nbuf[] = new byte[nsz];
System.arraycopy(buffer, 0, nbuf, 0, pos);
/*AtomicReferenceFieldUpdater是一个基于反射的工具类,
它能对指定类的指定的volatile引用字段进行原子更新。
(注意这个字段不能是private的) ,
从源码知getBufIfOpen返回的是值传递的protected volatile byte buf[]
*/
if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
// Can't replace buf if there was an async close.
// Note: This would need to be changed if fill()
// is ever made accessible to multiple threads.
// But for now, the only way CAS can fail is via close.
// assert buf == null;
throw new IOException("Stream closed");
}
buffer = nbuf;
}
//pos小于buf.length时,从底层流到缓冲区,使用InputStream的read(byte[])方法
count = pos; int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos;
}
总结:通过以上源码我们可以看到:
1)read(byte[])方法运行初始就用getBufIfOpen判断流关闭没有,因为缓冲流关闭后缓冲区失效,getBufIfOpen将抛出异常;
2)read(byte[])方法中的read1方法是该read底层,用来读取缓冲区buf的数据进指定数组的方法,而fill方法又是read1方法中,用来读取底层字节流到缓冲区buf的方法,层层封装外包;
3)read(byte[]) <-- read1(byte[]) <-- fill() <-- getInIfOpen().read(buf) <-- InputStream 层层外包,
这里getInIfOpen()返回一个非空底层流InputStream,并调用底层流的read(byte[])方法读取流数据到缓冲区buf,
所以当我们只是关闭底层流这些嵌套流也跟着“关闭”,但是会留下缓冲数组buf,这有时可以利用,有时要注意关闭避免浪费资源;
以下是close()的源码分析:
1 public void close() throws IOException {
2 byte[] buffer;
3 while ( (buffer = buf) != null) {
4 if (bufUpdater.compareAndSet(this, buffer, null)) { // 会将缓冲区buf的数据清空并释放缓冲区,也就是buf=null
5 InputStream input = in; //引用传递,input和in同指向节点流对象
6 in = null; //修改强引用,使底层流引用变量失效,即任何人都不能通过in去引用底层流了
7 if (input != null) //然后交给input单独来非空判断和执行关闭操作
8 input.close(); //调用节点流的close(),和native相关
9 return;
10 }
11 // Else retry in case a new buf was CASed in fill()
12 }
13 }
4)当BufferedInputStream缓冲区数据用完时,自动从底层输入流中补充数据(stream-->buf--read buf-->I)
5)关于read(byte[])缓冲区buf空间大小限制性能的问题:
(1)一开始使用缓冲流时,如果请求填充的长度len大于缓冲区大小buf.length,将直接使用底层流的read(byte[])方法,原因是扩充缓冲区的成本大于缓冲带来的便利;
(2)多次使用缓冲流后,一样如果请求填充的长度len大于缓冲区大小buf.length,为了数据的完整安全,在内部的fill()方法中扩充缓冲区大小,而这要付出相应成本限制性能,所以缓冲区大小要谨慎设定。
6)在缓冲区可用数据小于目标数组b的时候,使用System.arraycopy整体将缓冲区从pos位置起的数据覆盖到目标数组上
int cnt = (avail < len) ? avail : len; //cnt是要写入b的字节数,如果b中剩余字节数avail比要刷入的数据长度len大,则cnt为len System.arraycopy(getBufIfOpen(), pos, b, off, cnt); //复制指定范围非空buf数据到b
BufferedOutputStream工作流程
流程:I--write buf-->buf-->stream,我们通过两个write输出我们的数据,而数据暂时积聚在buf中,等待flush
1.当一个BufferedOutputStream被创建时,一个内部的缓冲区 byte[] buf = new byte[size] 也被建立,size默认是8192也就是默认创建一个8kb大小的缓存空间,
最终的数据去向由底层流决定,比如new FileOutputStream("a.txt")去向就是a.txt,而我们过滤流的数据来源是节点流!
2.BufferedOutputStream在内部缓冲区存储程序的输出数据,这样就不会每次调用write方法时,就把数据写到底层的输出流;
3.当BufferedOutputStream的内部缓冲区满或者它被刷新(flush),数据一次性写到底层的输出流。
constructor源码分析:
public BufferedOutputStream(OutputStream out) {
this(out, 8192);
} //这里与BufferedInputStream同理,不再赘述
public BufferedOutputStream(OutputStream out, int size) {
super(out);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
write(int)源码分析:
public synchronized void write(int b) throws IOException {
if (count >= buf.length) { //当count++到buf.length的长度,表明缓冲区已满
flushBuffer(); //刷出缓存到底层字节输出流
}
buf[count++] = (byte)b; //此时缓冲区本身未满或者flush后空了(count=0),先把b放在缓冲区buf中
} /*刷出内部的缓存到底层字节输出流*/
private void flushBuffer() throws IOException {
if (count > 0) {
out.write(buf, 0, count); //实质上利用底层流的write(byte[])
count = 0; //全部刷出,count=0,作为标志位与buf[count++]联合来刷新
}
}
write(byte[], int, int)源码分析:
public synchronized void write(byte b[], int off, int len) throws IOException { /* 在指定数组数据到buf时,如果数据的长度比buf长,
可能在传输过程中需要发出超长len,所以将buf中之前的工作数据刷出,
然后直接调用底层流的write(byte[])方法输出,
这个判断暗地里也限制了初始时就len过长的情况(count=0)
*/
if (len >= buf.length) {
flushBuffer();
out.write(b, off, len);
return;
} /*表明缓冲区已满,刷出*/
if (len > buf.length - count) {
flushBuffer();
} /*在经过上面的判断后,说明len<buf.length且count>0,
已使用过buf,只是剩余空间不足以承载,刷出数据后,
利用arraycopy将数据存入buf
*/
System.arraycopy(b, off, buf, count, len);
count += len; //count增加填充的字节数
}
flush()源码分析:
public synchronized void flush() throws IOException {
/*刷出缓冲区的数据到基流*/
flushBuffer(); /* 调用基流的flush方法,这里考虑到了嵌套流,
普通的节点流flush方法是空方法,
如果嵌套的依旧是一个带缓存的流,那么可递归每一层的flush
这迫使任何缓存输出的字节被写到底层流上
*/
out.flush();
}
总结:通过以上源码我们可以看到:
1)write(int)时,若buf已满,将自动刷出buf中的数据到流;
2)刷出到流的内部方法flushBuffer利用的是基流的write(byte[], int, int)方法;
3)没有close方法,只给关闭底层流,缓存输出流无需关闭;
4)flush方法调用基流的flush方法,这里考虑到了嵌套流,因为普通的节点流flush方法是空方法!
如果嵌套的依旧是一个带缓存的流,那么可递归flush,这迫使任何缓存输出的字节被写到底层流上;
5) write(byte[], int, int)时,
(1)如果数据的长度比buf长,可能在传输过程中需要发出超长len,所以将buf中之前的工作数据刷出,然后直接调用底层流的write(byte[])方法自行输出,这个判断暗地里也限制了初始时就len过长的情况(count=0);
(2)无需刷出缓存的情况下,使用arraycopy把要输出的byte[]数据,从count位置开始,拷贝到buf中。
和节点流ByteArrayInput/OutputStream的区别
1.ByteArrayInputStream是节点流;BufferedInputStream是过滤流;
2.ByteArrayInputStream需要使用者提供一个缓冲数组,是自带缓冲功能的流,由构造器传入;BufferedInputStream默认自己创建一个缓冲数组,默认4096长度,即4kB大小;
3.ByteArrayInputStream利用继承关系扩展流的功能;BufferedInputStream利用装饰模式扩展流的功能;
4.类中方法的原理都差不多,具体参阅源码
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/ package java.io; /**
* A <code>ByteArrayInputStream</code> contains
* an internal buffer that contains bytes that
* may be read from the stream. An internal
* counter keeps track of the next byte to
* be supplied by the <code>read</code> method.
* <p>
* Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an <tt>IOException</tt>.
*
* @author Arthur van Hoff
* @see java.io.StringBufferInputStream
* @since JDK1.0
*/
public
class ByteArrayInputStream extends InputStream { /**
* An array of bytes that was provided
* by the creator of the stream. Elements <code>buf[0]</code>
* through <code>buf[count-1]</code> are the
* only bytes that can ever be read from the
* stream; element <code>buf[pos]</code> is
* the next byte to be read.
*/
protected byte buf[]; /**
* The index of the next character to read from the input stream buffer.
* This value should always be nonnegative
* and not larger than the value of <code>count</code>.
* The next byte to be read from the input stream buffer
* will be <code>buf[pos]</code>.
*/
protected int pos; /**
* The currently marked position in the stream.
* ByteArrayInputStream objects are marked at position zero by
* default when constructed. They may be marked at another
* position within the buffer by the <code>mark()</code> method.
* The current buffer position is set to this point by the
* <code>reset()</code> method.
* <p>
* If no mark has been set, then the value of mark is the offset
* passed to the constructor (or 0 if the offset was not supplied).
*
* @since JDK1.1
*/
protected int mark = 0; /**
* The index one greater than the last valid character in the input
* stream buffer.
* This value should always be nonnegative
* and not larger than the length of <code>buf</code>.
* It is one greater than the position of
* the last byte within <code>buf</code> that
* can ever be read from the input stream buffer.
*/
protected int count; /**
* Creates a <code>ByteArrayInputStream</code>
* so that it uses <code>buf</code> as its
* buffer array.
* The buffer array is not copied.
* The initial value of <code>pos</code>
* is <code>0</code> and the initial value
* of <code>count</code> is the length of
* <code>buf</code>.
*
* @param buf the input buffer.
*/
public ByteArrayInputStream(byte buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
} /**
* Creates <code>ByteArrayInputStream</code>
* that uses <code>buf</code> as its
* buffer array. The initial value of <code>pos</code>
* is <code>offset</code> and the initial value
* of <code>count</code> is the minimum of <code>offset+length</code>
* and <code>buf.length</code>.
* The buffer array is not copied. The buffer's mark is
* set to the specified offset.
*
* @param buf the input buffer.
* @param offset the offset in the buffer of the first byte to read.
* @param length the maximum number of bytes to read from the buffer.
*/
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;
} /**
* Reads the next byte of data from this input stream. The value
* byte is returned as an <code>int</code> in the range
* <code>0</code> to <code>255</code>. If no byte is available
* because the end of the stream has been reached, the value
* <code>-1</code> is returned.
* <p>
* This <code>read</code> method
* cannot block.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream has been reached.
*/
public synchronized int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
} /**
* Reads up to <code>len</code> bytes of data into an array of bytes
* from this input stream.
* If <code>pos</code> equals <code>count</code>,
* then <code>-1</code> is returned to indicate
* end of file. Otherwise, the number <code>k</code>
* of bytes read is equal to the smaller of
* <code>len</code> and <code>count-pos</code>.
* If <code>k</code> is positive, then bytes
* <code>buf[pos]</code> through <code>buf[pos+k-1]</code>
* are copied into <code>b[off]</code> through
* <code>b[off+k-1]</code> in the manner performed
* by <code>System.arraycopy</code>. The
* value <code>k</code> is added into <code>pos</code>
* and <code>k</code> is returned.
* <p>
* This <code>read</code> method cannot block.
*
* @param b the buffer into which the data is read.
* @param off the start offset in the destination array <code>b</code>
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception NullPointerException If <code>b</code> is <code>null</code>.
* @exception IndexOutOfBoundsException If <code>off</code> is negative,
* <code>len</code> is negative, or <code>len</code> is greater than
* <code>b.length - off</code>
*/
public synchronized int read(byte b[], int off, int len) {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} 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;
} /**
* Skips <code>n</code> bytes of input from this input stream. Fewer
* bytes might be skipped if the end of the input stream is reached.
* The actual number <code>k</code>
* of bytes to be skipped is equal to the smaller
* of <code>n</code> and <code>count-pos</code>.
* The value <code>k</code> is added into <code>pos</code>
* and <code>k</code> is returned.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped.
*/
public synchronized long skip(long n) {
long k = count - pos;
if (n < k) {
k = n < 0 ? 0 : n;
} pos += k;
return k;
} /**
* Returns the number of remaining bytes that can be read (or skipped over)
* from this input stream.
* <p>
* The value returned is <code>count - pos</code>,
* which is the number of bytes remaining to be read from the input buffer.
*
* @return the number of remaining bytes that can be read (or skipped
* over) from this input stream without blocking.
*/
public synchronized int available() {
return count - pos;
} /**
* Tests if this <code>InputStream</code> supports mark/reset. The
* <code>markSupported</code> method of <code>ByteArrayInputStream</code>
* always returns <code>true</code>.
*
* @since JDK1.1
*/
public boolean markSupported() {
return true;
} /**
* Set the current marked position in the stream.
* ByteArrayInputStream objects are marked at position zero by
* default when constructed. They may be marked at another
* position within the buffer by this method.
* <p>
* If no mark has been set, then the value of the mark is the
* offset passed to the constructor (or 0 if the offset was not
* supplied).
*
* <p> Note: The <code>readAheadLimit</code> for this class
* has no meaning.
*
* @since JDK1.1
*/
public void mark(int readAheadLimit) {
mark = pos;
} /**
* Resets the buffer to the marked position. The marked position
* is 0 unless another position was marked or an offset was specified
* in the constructor.
*/
public synchronized void reset() {
pos = mark;
} /**
* Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an <tt>IOException</tt>.
*/
public void close() throws IOException {
} }
ByteArrayInputStream
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/ package java.io; import java.util.Arrays; /**
* This class implements an output stream in which the data is
* written into a byte array. The buffer automatically grows as data
* is written to it.
* The data can be retrieved using <code>toByteArray()</code> and
* <code>toString()</code>.
* <p>
* 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>.
*
* @author Arthur van Hoff
* @since JDK1.0
*/ public class ByteArrayOutputStream extends OutputStream { /**
* The buffer where data is stored.
*/
protected byte buf[]; /**
* The number of valid bytes in the buffer.
*/
protected int count; /**
* Creates a new byte array output stream. The buffer capacity is
* initially 32 bytes, though its size increases if necessary.
*/
public ByteArrayOutputStream() {
this(32);
} /**
* Creates a new byte array output stream, with a buffer capacity of
* the specified size, in bytes.
*
* @param size the initial size.
* @exception IllegalArgumentException if size is negative.
*/
public ByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException("Negative initial size: "
+ size);
}
buf = new byte[size];
} /**
* Increases the capacity if necessary to ensure that it can hold
* at least the number of elements specified by the minimum
* capacity argument.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if {@code minCapacity < 0}. This is
* interpreted as a request for the unsatisfiably large capacity
* {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}.
*/
private void ensureCapacity(int minCapacity) {
// overflow-conscious code
if (minCapacity - buf.length > 0)
grow(minCapacity);
} /**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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;
} /**
* Writes the specified byte to this byte array output stream.
*
* @param b the byte to be written.
*/
public synchronized void write(int b) {
ensureCapacity(count + 1);
buf[count] = (byte) b;
count += 1;
} /**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this byte array output stream.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
*/
public synchronized void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) - b.length > 0)) {
throw new IndexOutOfBoundsException();
}
ensureCapacity(count + len);
System.arraycopy(b, off, buf, count, len);
count += len;
} /**
* Writes the complete contents of this byte array output stream to
* the specified output stream argument, as if by calling the output
* stream's write method using <code>out.write(buf, 0, count)</code>.
*
* @param out the output stream to which to write the data.
* @exception IOException if an I/O error occurs.
*/
public synchronized void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count);
} /**
* Resets the <code>count</code> field of this byte array output
* stream to zero, so that all currently accumulated output in the
* output stream is discarded. The output stream can be used again,
* reusing the already allocated buffer space.
*
* @see java.io.ByteArrayInputStream#count
*/
public synchronized void reset() {
count = 0;
} /**
* Creates a newly allocated byte array. Its size is the current
* size of this output stream and the valid contents of the buffer
* have been copied into it.
*
* @return the current contents of this output stream, as a byte array.
* @see java.io.ByteArrayOutputStream#size()
*/
public synchronized byte toByteArray()[] {
return Arrays.copyOf(buf, count);
} /**
* Returns the current size of the buffer.
*
* @return the value of the <code>count</code> field, which is the number
* of valid bytes in this output stream.
* @see java.io.ByteArrayOutputStream#count
*/
public synchronized int size() {
return count;
} /**
* Converts the buffer's contents into a string decoding bytes using the
* platform's default character set. The length of the new <tt>String</tt>
* is a function of the character set, and hence may not be equal to the
* size of the buffer.
*
* <p> This method always replaces malformed-input and unmappable-character
* sequences with the default replacement string for the platform's
* default character set. The {@linkplain java.nio.charset.CharsetDecoder}
* class should be used when more control over the decoding process is
* required.
*
* @return String decoded from the buffer's contents.
* @since JDK1.1
*/
public synchronized String toString() {
return new String(buf, 0, count);
} /**
* Converts the buffer's contents into a string by decoding the bytes using
* the named {@link java.nio.charset.Charset charset}. The length of the new
* <tt>String</tt> is a function of the charset, and hence may not be equal
* to the length of the byte array.
*
* <p> This method always replaces malformed-input and unmappable-character
* sequences with this charset's default replacement string. The {@link
* java.nio.charset.CharsetDecoder} class should be used when more control
* over the decoding process is required.
*
* @param charsetName the name of a supported
* {@link java.nio.charset.Charset charset}
* @return String decoded from the buffer's contents.
* @exception UnsupportedEncodingException
* If the named charset is not supported
* @since JDK1.1
*/
public synchronized String toString(String charsetName)
throws UnsupportedEncodingException
{
return new String(buf, 0, count, charsetName);
} /**
* Creates a newly allocated string. Its size is the current size of
* the output stream and the valid contents of the buffer have been
* copied into it. Each character <i>c</i> in the resulting string is
* constructed from the corresponding element <i>b</i> in the byte
* array such that:
* <blockquote><pre>
* c == (char)(((hibyte & 0xff) << 8) | (b & 0xff))
* </pre></blockquote>
*
* @deprecated This method does not properly convert bytes into characters.
* As of JDK 1.1, the preferred way to do this is via the
* <code>toString(String enc)</code> method, which takes an encoding-name
* argument, or the <code>toString()</code> method, which uses the
* platform's default character encoding.
*
* @param hibyte the high byte of each resulting Unicode character.
* @return the current contents of the output stream, as a string.
* @see java.io.ByteArrayOutputStream#size()
* @see java.io.ByteArrayOutputStream#toString(String)
* @see java.io.ByteArrayOutputStream#toString()
*/
@Deprecated
public synchronized String toString(int hibyte) {
return new String(buf, hibyte, 0, 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>.
*/
public void close() throws IOException {
} }
ByteArrayOutputStream