java过滤流_Java IO 过滤流 BufferedInput/OutputStream

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,而我们过滤流的数据来源是节点流!

1 private static int DEFAULT_BUFFER_SIZE = 8192; //默认缓冲数组长度大小,折合单位有8kb2 protected volatile bytebuf[]; //底层维护的缓冲数组变量3

4 publicBufferedInputStream(InputStream in) {5 this(in, DEFAULT_BUFFER_SIZE); //默认81926 }7

8

9 public BufferedInputStream(InputStream in, intsize) {10 super(in); //引用基类FilterInputStream的构造方法,基类有底层流变量11 if (size <= 0) {12 throw new IllegalArgumentException("Buffer size <= 0");13 }14 buf = new byte[size]; //初始化缓冲数组,指定大小为size15 }

2.当BufferedInputStream的read方法被调用时,数据将从缓冲区中移出,而不是底层的输入流;

3.当BufferedInputStream缓冲区数据用完时,他自动从底层输入流中补充数据。

read()源码分析:

//返回下一个数据字节,如果到达流末尾则返回-1,数据流向返回值!

1 public synchronized int read() throwsIOException {2 if (pos >=count) { //当缓存指针等于或者超过count时,说明buf已满3 fill(); //fill()从节点流中读取数据存放到buf缓冲区4 if (pos >=count)5 return -1;6 }7 return getBufIfOpen()[pos++] & 0xff; //得到非空buf缓冲当前索引为pos位置的一字节数据,pos++ 缓冲区指针移动一位8 }9

10 //getBufIfOpen对buf进行非空判断

11 private byte[] getBufIfOpen() throwsIOException {12 byte[] buffer =buf; //用一个引用变量引用buf13 if (buffer == null)14 throw new IOException("Stream closed");15 returnbuffer; //返回buffer,实质上指向buf16 }

read(byte[], int, int)源码分析 :

//pos是起始/下一次读取buffer的位置,

//markpos是最新一次已读取的位置,

//count是缓冲数组被填充的大小-1(因为是作为index存在的,从0开始)

//len是b要读取的最大字节数

1 //返回读取的字节数,如果流到达末尾返回-1,数据流向b数组!

2 public synchronized int read(byte b[], int off, intlen)3 throwsIOException4 {5

6 /*这里只做检查,流关闭则提前抛出,以避免拖到fill()中的getBufIfOpen()再抛出的情况

7 private byte[] getBufIfOpen() throws IOException {8 byte[] buffer = buf; //引用传递,指向当前buf变量指向的内存9 if (buffer == null) //就为了这个非空判断而已10 throw new IOException("Stream closed");11 return buffer; //这里返回值是没人接收的,方法结束抛弃局部变量buffer,不对buf造成影响12 }13 */

14 getBufIfOpen(); //Check for closed stream 关闭流将抛出异常15 //指定数组的越界判断

16 if ((off | len | (off + len) | (b.length - (off + len))) < 0) {17 throw newIndexOutOfBoundsException();18 } else if (len == 0) {19 return 0;20 }21

22 int n = 0;23 //循环写数据到b,直到buffer数据不足返回-1,此时nread已累加记录

24 for(;;) {25 int nread = read1(b, off + n, len -n);//读缓冲区数据到b26 if (nread <= 0)27 return (n == 0) ?nread : n;28 n +=nread;29 //读完指定长度时返回

30 if (n >=len)31 returnn;32 //if not closed but no bytes available, return33 //没读完指定长度,但缓冲区没数据时返回当前n

34 InputStream input =in;35 if (input != null && input.available() <= 0)36 returnn;37 }38 }39

40

41 /**

42 * read1方法是该read底层用来读取缓冲区buf的数据进指定数组的方法43 * 而fill方法又是read1方法中用来读取底层字节流到缓冲区buf的方法44 * 读取数据写进指定数组的一部分,必要时每次从底层流尽量读取数据45 */

46 private int read1(byte[] b, int off, int len) throwsIOException {47 int avail = count -pos; //开始时为048 if (avail <= 0) {49 /*如果所请求的长度大于等于缓冲区,并且还没读取过buf

50         (即刚开始使用时,扩充缓冲区成本不值得,回归底层流),51 就没必要用缓冲区了,将直接从底层流读取数据。52 */

53 if (len >= getBufIfOpen().length && markpos < 0) {54 //直接调用底层流的read方法,写进指定的内存b

55 returngetInIfOpen().read(b, off, len);56 }57 //请求fill()方法来读取底层流数据(多次使用后如果长度大于缓冲区,为了数据保护,将扩充缓冲区)

58 fill();59 avail = count -pos; //avail是60 if (avail <= 0) return -1;61 }62 int cnt = (avail < len) ?avail : len; //cnt是要写入b的字节数,如果b中剩余字节数avail比要刷入的数据长度len大,则cnt为len63 System.arraycopy(getBufIfOpen(), pos, b, off, cnt); //复制指定范围非空buf数据到b64 pos +=cnt;65 returncnt;66 }67

68

69 //fill()方法填充空间,是底层用来读取流数据到缓冲区buf

70 /**

71 * Fills the buffer with more data, taking into account72 * shuffling and other tricks for dealing with marks.73 * Assumes that it is being called by a synchronized method.74 * This method also assumes that all data has already been read in,75 * hence pos > count.76 */

77 private void fill() throwsIOException {78 byte[] buffer =getBufIfOpen();79 //pos是起始/下一次读取buffer的位置,markpos是最新一次已读取的位置,count是缓冲数组被填充的大小-1(因为是作为index存在的,从0开始)80 //起始小于零表明没有pos移动,从源码可知

81 if (markpos < 0)82 pos = 0; /*no mark: throw away the buffer*/

83 //当pos比buffer更长时,即

84 else if (pos >= buffer.length) /*no room left in buffer*/

85 //markpos也有前移时,数组自我复制丢弃早期部分

86 if (markpos > 0) { /*can throw away early part of the buffer*/

87 int sz = pos -markpos;88 System.arraycopy(buffer, markpos, buffer, 0, sz);89 pos =sz;90 markpos = 0;91 //buffer大小超过理论规模时,重置,通过改变pos“丢弃”缓冲区内容

92 } else if (buffer.length >=marklimit) {93 markpos = -1; /*buffer got too big, invalidate mark*/

94 pos = 0; /*drop buffer contents*/

95 //buffer大小超过本地VM内存限制:MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8

96 } else if (buffer.length >=MAX_BUFFER_SIZE) {97 throw new OutOfMemoryError("Required array size too large");98 } else { /*grow buffer*/ //没有顾忌时,扩充缓冲区大小

99 int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?

100 pos * 2: MAX_BUFFER_SIZE;101 if (nsz >marklimit)102 nsz =marklimit;103 byte nbuf[] = new byte[nsz];104 System.arraycopy(buffer, 0, nbuf, 0, pos);105 /*AtomicReferenceFieldUpdater是一个基于反射的工具类,106 它能对指定类的指定的volatile引用字段进行原子更新。107 (注意这个字段不能是private的) ,108 从源码知getBufIfOpen返回的是值传递的protected volatile byte buf[]109 */

110 if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {111 //Can't replace buf if there was an async close.112 //Note: This would need to be changed if fill()113 //is ever made accessible to multiple threads.114 //But for now, the only way CAS can fail is via close.115 //assert buf == null;

116 throw new IOException("Stream closed");117 }118 buffer =nbuf;119 }120 //pos小于buf.length时,从底层流到缓冲区,使用InputStream的read(byte[])方法

121 count =pos;122 int n = getInIfOpen().read(buffer, pos, buffer.length -pos);123 if (n > 0)124 count = n +pos;125 }126

总结:通过以上源码我们可以看到:

1)read(byte[])方法运行初始就用getBufIfOpen判断流关闭没有,因为缓冲流关闭后缓冲区失效,getBufIfOpen将抛出异常;

2)read(byte[])方法中的read1方法是该read底层,用来读取缓冲区buf的数据进指定数组的方法,而fill方法又是read1方法中,用来读取底层字节流到缓冲区buf的方法,层层封装外包;

3)read(byte[])

这里getInIfOpen()返回一个非空底层流InputStream,并调用底层流的read(byte[])方法读取流数据到缓冲区buf,

所以当我们只是关闭底层流这些嵌套流也跟着“关闭”,但是会留下缓冲数组buf,这有时可以利用,有时要注意关闭避免浪费资源;

以下是close()的源码分析:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 1 public void close() throwsIOException {2 2 byte[] buffer;3 3 while ( (buffer = buf) != null) {4 4 if (bufUpdater.compareAndSet(this, buffer, null)) { //会将缓冲区buf的数据清空并释放缓冲区,也就是buf=null

5 5 InputStream input = in; //引用传递,input和in同指向节点流对象

6 6 in = null; //修改强引用,使底层流引用变量失效,即任何人都不能通过in去引用底层流了

7 7 if (input != null) //然后交给input单独来非空判断和执行关闭操作

8 8 input.close(); //调用节点流的close(),和native相关

9 9 return;10 10}11 11 //Else retry in case a new buf was CASed in fill()

12 12}13 13 }

View Code

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位置起的数据覆盖到目标数组上

1       int cnt = (avail < len) ? avail : len; //cnt是要写入b的字节数,如果b中剩余字节数avail比要刷入的数据长度len大,则cnt为len

2

3       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源码分析:

1 publicBufferedOutputStream(OutputStream out) {2 this(out, 8192);3 }4

5 //这里与BufferedInputStream同理,不再赘述

6 public BufferedOutputStream(OutputStream out, intsize) {7 super(out);8 if (size <= 0) {9 throw new IllegalArgumentException("Buffer size <= 0");10 }11 buf = new byte[size];12 }

write(int)源码分析:

1 public synchronized void write(int b) throwsIOException {2 if (count >= buf.length) { //当count++到buf.length的长度,表明缓冲区已满

3 flushBuffer(); //刷出缓存到底层字节输出流

4 }5 buf[count++] = (byte)b; //此时缓冲区本身未满或者flush后空了(count=0),先把b放在缓冲区buf中

6 }7

8

9 /*刷出内部的缓存到底层字节输出流*/

10 private void flushBuffer() throwsIOException {11 if (count > 0) {12 out.write(buf, 0, count); //实质上利用底层流的write(byte[])

13 count = 0; //全部刷出,count=0,作为标志位与buf[count++]联合来刷新

14 }15 }

write(byte[], int, int)源码分析:

1 public synchronized void write(byte b[], int off, int len) throwsIOException {2

3 /*在指定数组数据到buf时,如果数据的长度比buf长,4 可能在传输过程中需要发出超长len,所以将buf中之前的工作数据刷出,5 然后直接调用底层流的write(byte[])方法输出,6 这个判断暗地里也限制了初始时就len过长的情况(count=0)7 */

8 if (len >=buf.length) {9 flushBuffer();10 out.write(b, off, len);11 return;12 }13

14 /*表明缓冲区已满,刷出*/

15 if (len > buf.length -count) {16 flushBuffer();17 }18

19 /*在经过上面的判断后,说明len0,20 已使用过buf,只是剩余空间不足以承载,刷出数据后,21 利用arraycopy将数据存入buf22 */

23 System.arraycopy(b, off, buf, count, len);24 count += len; //count增加填充的字节数

25 }

flush()源码分析:

1 public synchronized void flush() throwsIOException {2 /*刷出缓冲区的数据到基流*/

3 flushBuffer();4

5 /*调用基流的flush方法,这里考虑到了嵌套流,6 普通的节点流flush方法是空方法,7 如果嵌套的依旧是一个带缓存的流,那么可递归每一层的flush8 这迫使任何缓存输出的字节被写到底层流上9 */

10 out.flush();11 }

总结:通过以上源码我们可以看到:

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.类中方法的原理都差不多,具体参阅源码

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 /*

2 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.3 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.4 *5 *6 *7 *8 *9 *10 *11 *12 *13 *14 *15 *16 *17 *18 *19 *20 *21 *22 *23 *24 */

25

26 packagejava.io;27

28 /**

29 * A ByteArrayInputStream contains30 * an internal buffer that contains bytes that31 * may be read from the stream. An internal32 * counter keeps track of the next byte to33 * be supplied by the read method.34 *

35 * Closing a ByteArrayInputStream has no effect. The methods in36 * this class can be called after the stream has been closed without37 * generating an IOException.38 *39 *@authorArthur van Hoff40 *@seejava.io.StringBufferInputStream41 *@sinceJDK1.042 */

43 public

44 class ByteArrayInputStream extendsInputStream {45

46 /**

47 * An array of bytes that was provided48 * by the creator of the stream. Elements buf[0]49 * through buf[count-1] are the50 * only bytes that can ever be read from the51 * stream; element buf[pos] is52 * the next byte to be read.53 */

54 protected bytebuf[];55

56 /**

57 * The index of the next character to read from the input stream buffer.58 * This value should always be nonnegative59 * and not larger than the value of count.60 * The next byte to be read from the input stream buffer61 * will be buf[pos].62 */

63 protected intpos;64

65 /**

66 * The currently marked position in the stream.67 * ByteArrayInputStream objects are marked at position zero by68 * default when constructed. They may be marked at another69 * position within the buffer by the mark() method.70 * The current buffer position is set to this point by the71 * reset() method.72 *

73 * If no mark has been set, then the value of mark is the offset74 * passed to the constructor (or 0 if the offset was not supplied).75 *76 *@sinceJDK1.177 */

78 protected int mark = 0;79

80 /**

81 * The index one greater than the last valid character in the input82 * stream buffer.83 * This value should always be nonnegative84 * and not larger than the length of buf.85 * It is one greater than the position of86 * the last byte within buf that87 * can ever be read from the input stream buffer.88 */

89 protected intcount;90

91 /**

92 * Creates a ByteArrayInputStream93 * so that it uses buf as its94 * buffer array.95 * The buffer array is not copied.96 * The initial value of pos97 * is 0 and the initial value98 * of count is the length of99 * buf.100 *101 *@parambuf the input buffer.102 */

103 public ByteArrayInputStream(bytebuf[]) {104 this.buf =buf;105 this.pos = 0;106 this.count =buf.length;107 }108

109 /**

110 * Creates ByteArrayInputStream111 * that uses buf as its112 * buffer array. The initial value of pos113 * is offset and the initial value114 * of count is the minimum of offset+length115 * and buf.length.116 * The buffer array is not copied. The buffer's mark is117 * set to the specified offset.118 *119 *@parambuf the input buffer.120 *@paramoffset the offset in the buffer of the first byte to read.121 *@paramlength the maximum number of bytes to read from the buffer.122 */

123 public ByteArrayInputStream(byte buf[], int offset, intlength) {124 this.buf =buf;125 this.pos =offset;126 this.count = Math.min(offset +length, buf.length);127 this.mark =offset;128 }129

130 /**

131 * Reads the next byte of data from this input stream. The value132 * byte is returned as an int in the range133 * 0 to 255. If no byte is available134 * because the end of the stream has been reached, the value135 * -1 is returned.136 *

137 * This read method138 * cannot block.139 *140 *@returnthe next byte of data, or -1 if the end of the141 * stream has been reached.142 */

143 public synchronized intread() {144 return (pos < count) ? (buf[pos++] & 0xff) : -1;145 }146

147 /**

148 * Reads up to len bytes of data into an array of bytes149 * from this input stream.150 * If pos equals count,151 * then -1 is returned to indicate152 * end of file. Otherwise, the number k153 * of bytes read is equal to the smaller of154 * len and count-pos.155 * If k is positive, then bytes156 * buf[pos] through buf[pos+k-1]157 * are copied into b[off] through158 * b[off+k-1] in the manner performed159 * by System.arraycopy. The160 * value k is added into pos161 * and k is returned.162 *

163 * This read method cannot block.164 *165 *@paramb the buffer into which the data is read.166 *@paramoff the start offset in the destination array b167 *@paramlen the maximum number of bytes read.168 *@returnthe total number of bytes read into the buffer, or169 * -1 if there is no more data because the end of170 * the stream has been reached.171 *@exceptionNullPointerException If b is null.172 *@exceptionIndexOutOfBoundsException If off is negative,173 * len is negative, or len is greater than174 * b.length - off175 */

176 public synchronized int read(byte b[], int off, intlen) {177 if (b == null) {178 throw newNullPointerException();179 } else if (off < 0 || len < 0 || len > b.length -off) {180 throw newIndexOutOfBoundsException();181 }182

183 if (pos >=count) {184 return -1;185 }186

187 int avail = count -pos;188 if (len >avail) {189 len =avail;190 }191 if (len <= 0) {192 return 0;193 }194 System.arraycopy(buf, pos, b, off, len);195 pos +=len;196 returnlen;197 }198

199 /**

200 * Skips n bytes of input from this input stream. Fewer201 * bytes might be skipped if the end of the input stream is reached.202 * The actual number k203 * of bytes to be skipped is equal to the smaller204 * of n and count-pos.205 * The value k is added into pos206 * and k is returned.207 *208 *@paramn the number of bytes to be skipped.209 *@returnthe actual number of bytes skipped.210 */

211 public synchronized long skip(longn) {212 long k = count -pos;213 if (n

217 pos +=k;218 returnk;219 }220

221 /**

222 * Returns the number of remaining bytes that can be read (or skipped over)223 * from this input stream.224 *

225 * The value returned is count - pos,226 * which is the number of bytes remaining to be read from the input buffer.227 *228 *@returnthe number of remaining bytes that can be read (or skipped229 * over) from this input stream without blocking.230 */

231 public synchronized intavailable() {232 return count -pos;233 }234

235 /**

236 * Tests if this InputStream supports mark/reset. The237 * markSupported method of ByteArrayInputStream238 * always returns true.239 *240 *@sinceJDK1.1241 */

242 public booleanmarkSupported() {243 return true;244 }245

246 /**

247 * Set the current marked position in the stream.248 * ByteArrayInputStream objects are marked at position zero by249 * default when constructed. They may be marked at another250 * position within the buffer by this method.251 *

252 * If no mark has been set, then the value of the mark is the253 * offset passed to the constructor (or 0 if the offset was not254 * supplied).255 *256 *

Note: The readAheadLimit for this class257 * has no meaning.258 *259 *@sinceJDK1.1260 */

261 public void mark(intreadAheadLimit) {262 mark =pos;263 }264

265 /**

266 * Resets the buffer to the marked position. The marked position267 * is 0 unless another position was marked or an offset was specified268 * in the constructor.269 */

270 public synchronized voidreset() {271 pos =mark;272 }273

274 /**

275 * Closing a ByteArrayInputStream has no effect. The methods in276 * this class can be called after the stream has been closed without277 * generating an IOException.278 */

279 public void close() throwsIOException {280 }281

282 }

ByteArrayInputStream

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 /*

2 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.3 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.4 *5 *6 *7 *8 *9 *10 *11 *12 *13 *14 *15 *16 *17 *18 *19 *20 *21 *22 *23 *24 */

25

26 packagejava.io;27

28 importjava.util.Arrays;29

30 /**

31 * This class implements an output stream in which the data is32 * written into a byte array. The buffer automatically grows as data33 * is written to it.34 * The data can be retrieved using toByteArray() and35 * toString().36 *

37 * Closing a ByteArrayOutputStream has no effect. The methods in38 * this class can be called after the stream has been closed without39 * generating an IOException.40 *41 *@authorArthur van Hoff42 *@sinceJDK1.043 */

44

45 public class ByteArrayOutputStream extendsOutputStream {46

47 /**

48 * The buffer where data is stored.49 */

50 protected bytebuf[];51

52 /**

53 * The number of valid bytes in the buffer.54 */

55 protected intcount;56

57 /**

58 * Creates a new byte array output stream. The buffer capacity is59 * initially 32 bytes, though its size increases if necessary.60 */

61 publicByteArrayOutputStream() {62 this(32);63 }64

65 /**

66 * Creates a new byte array output stream, with a buffer capacity of67 * the specified size, in bytes.68 *69 *@paramsize the initial size.70 *@exceptionIllegalArgumentException if size is negative.71 */

72 public ByteArrayOutputStream(intsize) {73 if (size < 0) {74 throw new IllegalArgumentException("Negative initial size: "

75 +size);76 }77 buf = new byte[size];78 }79

80 /**

81 * Increases the capacity if necessary to ensure that it can hold82 * at least the number of elements specified by the minimum83 * capacity argument.84 *85 *@paramminCapacity the desired minimum capacity86 *@throwsOutOfMemoryError if {@codeminCapacity < 0}. This is87 * interpreted as a request for the unsatisfiably large capacity88 * {@code(long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}.89 */

90 private void ensureCapacity(intminCapacity) {91 //overflow-conscious code

92 if (minCapacity - buf.length > 0)93 grow(minCapacity);94 }95

96 /**

97 * The maximum size of array to allocate.98 * Some VMs reserve some header words in an array.99 * Attempts to allocate larger arrays may result in100 * OutOfMemoryError: Requested array size exceeds VM limit101 */

102 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;103

104 /**

105 * Increases the capacity to ensure that it can hold at least the106 * number of elements specified by the minimum capacity argument.107 *108 *@paramminCapacity the desired minimum capacity109 */

110 private void grow(intminCapacity) {111 //overflow-conscious code

112 int oldCapacity =buf.length;113 int newCapacity = oldCapacity << 1;114 if (newCapacity - minCapacity < 0)115 newCapacity =minCapacity;116 if (newCapacity - MAX_ARRAY_SIZE > 0)117 newCapacity =hugeCapacity(minCapacity);118 buf =Arrays.copyOf(buf, newCapacity);119 }120

121 private static int hugeCapacity(intminCapacity) {122 if (minCapacity < 0) //overflow

123 throw newOutOfMemoryError();124 return (minCapacity > MAX_ARRAY_SIZE) ?

125 Integer.MAX_VALUE :126 MAX_ARRAY_SIZE;127 }128

129 /**

130 * Writes the specified byte to this byte array output stream.131 *132 *@paramb the byte to be written.133 */

134 public synchronized void write(intb) {135 ensureCapacity(count + 1);136 buf[count] = (byte) b;137 count += 1;138 }139

140 /**

141 * Writes len bytes from the specified byte array142 * starting at offset off to this byte array output stream.143 *144 *@paramb the data.145 *@paramoff the start offset in the data.146 *@paramlen the number of bytes to write.147 */

148 public synchronized void write(byte b[], int off, intlen) {149 if ((off < 0) || (off > b.length) || (len < 0) ||

150 ((off + len) - b.length > 0)) {151 throw newIndexOutOfBoundsException();152 }153 ensureCapacity(count +len);154 System.arraycopy(b, off, buf, count, len);155 count +=len;156 }157

158 /**

159 * Writes the complete contents of this byte array output stream to160 * the specified output stream argument, as if by calling the output161 * stream's write method using out.write(buf, 0, count).162 *163 *@paramout the output stream to which to write the data.164 *@exceptionIOException if an I/O error occurs.165 */

166 public synchronized void writeTo(OutputStream out) throwsIOException {167 out.write(buf, 0, count);168 }169

170 /**

171 * Resets the count field of this byte array output172 * stream to zero, so that all currently accumulated output in the173 * output stream is discarded. The output stream can be used again,174 * reusing the already allocated buffer space.175 *176 *@seejava.io.ByteArrayInputStream#count177 */

178 public synchronized voidreset() {179 count = 0;180 }181

182 /**

183 * Creates a newly allocated byte array. Its size is the current184 * size of this output stream and the valid contents of the buffer185 * have been copied into it.186 *187 *@returnthe current contents of this output stream, as a byte array.188 *@seejava.io.ByteArrayOutputStream#size()189 */

190 public synchronized bytetoByteArray()[] {191 returnArrays.copyOf(buf, count);192 }193

194 /**

195 * Returns the current size of the buffer.196 *197 *@returnthe value of the count field, which is the number198 * of valid bytes in this output stream.199 *@seejava.io.ByteArrayOutputStream#count200 */

201 public synchronized intsize() {202 returncount;203 }204

205 /**

206 * Converts the buffer's contents into a string decoding bytes using the207 * platform's default character set. The length of the new String208 * is a function of the character set, and hence may not be equal to the209 * size of the buffer.210 *211 *

This method always replaces malformed-input and unmappable-character212 * sequences with the default replacement string for the platform's213 * default character set. The {@linkplainjava.nio.charset.CharsetDecoder}214 * class should be used when more control over the decoding process is215 * required.216 *217 *@returnString decoded from the buffer's contents.218 *@sinceJDK1.1219 */

220 public synchronizedString toString() {221 return new String(buf, 0, count);222 }223

224 /**

225 * Converts the buffer's contents into a string by decoding the bytes using226 * the named {@linkjava.nio.charset.Charset charset}. The length of the new227 * String is a function of the charset, and hence may not be equal228 * to the length of the byte array.229 *230 *

This method always replaces malformed-input and unmappable-character231 * sequences with this charset's default replacement string. The {@link

232 * java.nio.charset.CharsetDecoder} class should be used when more control233 * over the decoding process is required.234 *235 *@paramcharsetName the name of a supported236 * {@linkjava.nio.charset.Charset charset}237 *@returnString decoded from the buffer's contents.238 *@exceptionUnsupportedEncodingException239 * If the named charset is not supported240 *@sinceJDK1.1241 */

242 public synchronizedString toString(String charsetName)243 throwsUnsupportedEncodingException244 {245 return new String(buf, 0, count, charsetName);246 }247

248 /**

249 * Creates a newly allocated string. Its size is the current size of250 * the output stream and the valid contents of the buffer have been251 * copied into it. Each character c in the resulting string is252 * constructed from the corresponding element b in the byte253 * array such that:254 *

255 *     c == (char)(((hibyte & 0xff) << 8) | (b & 0xff))256 * 
257 *258 *@deprecatedThis method does not properly convert bytes into characters.259 * As of JDK 1.1, the preferred way to do this is via the260 * toString(String enc) method, which takes an encoding-name261 * argument, or the toString() method, which uses the262 * platform's default character encoding.263 *264 *@paramhibyte the high byte of each resulting Unicode character.265 *@returnthe current contents of the output stream, as a string.266 *@seejava.io.ByteArrayOutputStream#size()267 *@seejava.io.ByteArrayOutputStream#toString(String)268 *@seejava.io.ByteArrayOutputStream#toString()269 */

270 @Deprecated271 public synchronized String toString(inthibyte) {272 return new String(buf, hibyte, 0, count);273 }274

275 /**

276 * Closing a ByteArrayOutputStream has no effect. The methods in277 * this class can be called after the stream has been closed without278 * generating an IOException.279 */

280 public void close() throwsIOException {281 }282

283 }

ByteArrayOutputStream

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值