1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.io; 19 20import java.util.Arrays; 21 22/** 23 * A specialized {@link OutputStream} for class for writing content to an 24 * (internal) byte array. As bytes are written to this stream, the byte array 25 * may be expanded to hold more bytes. When the writing is considered to be 26 * finished, a copy of the byte array can be requested from the class. 27 * 28 * @see ByteArrayInputStream 29 */ 30public class ByteArrayOutputStream extends OutputStream { 31 /** 32 * The byte array containing the bytes written. 33 */ 34 protected byte[] buf; 35 36 /** 37 * The number of bytes written. 38 */ 39 protected int count; 40 41 /** 42 * Constructs a new ByteArrayOutputStream with a default size of 32 bytes. 43 * If more than 32 bytes are written to this instance, the underlying byte 44 * array will expand. 45 */ 46 public ByteArrayOutputStream() { 47 buf = new byte[32]; 48 } 49 50 /** 51 * Constructs a new {@code ByteArrayOutputStream} with a default size of 52 * {@code size} bytes. If more than {@code size} bytes are written to this 53 * instance, the underlying byte array will expand. 54 * 55 * @param size 56 * initial size for the underlying byte array, must be 57 * non-negative. 58 * @throws IllegalArgumentException 59 * if {@code size} < 0. 60 */ 61 public ByteArrayOutputStream(int size) { 62 if (size >= 0) { 63 buf = new byte[size]; 64 } else { 65 throw new IllegalArgumentException("size < 0"); 66 } 67 } 68 69 /** 70 * Closes this stream. This releases system resources used for this stream. 71 * 72 * @throws IOException 73 * if an error occurs while attempting to close this stream. 74 */ 75 @Override 76 public void close() throws IOException { 77 /** 78 * Although the spec claims "A closed stream cannot perform output 79 * operations and cannot be reopened.", this implementation must do 80 * nothing. 81 */ 82 super.close(); 83 } 84 85 private void expand(int i) { 86 /* Can the buffer handle @i more bytes, if not expand it */ 87 if (count + i <= buf.length) { 88 return; 89 } 90 91 byte[] newbuf = new byte[(count + i) * 2]; 92 System.arraycopy(buf, 0, newbuf, 0, count); 93 buf = newbuf; 94 } 95 96 /** 97 * Resets this stream to the beginning of the underlying byte array. All 98 * subsequent writes will overwrite any bytes previously stored in this 99 * stream. 100 */ 101 public synchronized void reset() { 102 count = 0; 103 } 104 105 /** 106 * Returns the total number of bytes written to this stream so far. 107 * 108 * @return the number of bytes written to this stream. 109 */ 110 public int size() { 111 return count; 112 } 113 114 /** 115 * Returns the contents of this ByteArrayOutputStream as a byte array. Any 116 * changes made to the receiver after returning will not be reflected in the 117 * byte array returned to the caller. 118 * 119 * @return this stream's current contents as a byte array. 120 */ 121 public synchronized byte[] toByteArray() { 122 byte[] newArray = new byte[count]; 123 System.arraycopy(buf, 0, newArray, 0, count); 124 return newArray; 125 } 126 127 /** 128 * Returns the contents of this ByteArrayOutputStream as a string. Any 129 * changes made to the receiver after returning will not be reflected in the 130 * string returned to the caller. 131 * 132 * @return this stream's current contents as a string. 133 */ 134 135 @Override 136 public String toString() { 137 return new String(buf, 0, count); 138 } 139 140 /** 141 * Returns the contents of this ByteArrayOutputStream as a string. Each byte 142 * {@code b} in this stream is converted to a character {@code c} using the 143 * following function: 144 * {@code c == (char)(((hibyte & 0xff) << 8) | (b & 0xff))}. This method is 145 * deprecated and either {@link #toString()} or {@link #toString(String)} 146 * should be used. 147 * 148 * @param hibyte 149 * the high byte of each resulting Unicode character. 150 * @return this stream's current contents as a string with the high byte set 151 * to {@code hibyte}. 152 * @deprecated Use {@link #toString()}. 153 */ 154 @Deprecated 155 public String toString(int hibyte) { 156 char[] newBuf = new char[size()]; 157 for (int i = 0; i < newBuf.length; i++) { 158 newBuf[i] = (char) (((hibyte & 0xff) << 8) | (buf[i] & 0xff)); 159 } 160 return new String(newBuf); 161 } 162 163 /** 164 * Returns the contents of this ByteArrayOutputStream as a string converted 165 * according to the encoding declared in {@code charsetName}. 166 * 167 * @param charsetName 168 * a string representing the encoding to use when translating 169 * this stream to a string. 170 * @return this stream's current contents as an encoded string. 171 * @throws UnsupportedEncodingException 172 * if the provided encoding is not supported. 173 */ 174 public String toString(String charsetName) throws UnsupportedEncodingException { 175 return new String(buf, 0, count, charsetName); 176 } 177 178 /** 179 * Writes {@code count} bytes from the byte array {@code buffer} starting at 180 * offset {@code index} to this stream. 181 * 182 * @param buffer 183 * the buffer to be written. 184 * @param offset 185 * the initial position in {@code buffer} to retrieve bytes. 186 * @param len 187 * the number of bytes of {@code buffer} to write. 188 * @throws NullPointerException 189 * if {@code buffer} is {@code null}. 190 * @throws IndexOutOfBoundsException 191 * if {@code offset < 0} or {@code len < 0}, or if 192 * {@code offset + len} is greater than the length of 193 * {@code buffer}. 194 */ 195 @Override 196 public synchronized void write(byte[] buffer, int offset, int len) { 197 Arrays.checkOffsetAndCount(buffer.length, offset, len); 198 if (len == 0) { 199 return; 200 } 201 expand(len); 202 System.arraycopy(buffer, offset, buf, this.count, len); 203 this.count += len; 204 } 205 206 /** 207 * Writes the specified byte {@code oneByte} to the OutputStream. Only the 208 * low order byte of {@code oneByte} is written. 209 * 210 * @param oneByte 211 * the byte to be written. 212 */ 213 @Override 214 public synchronized void write(int oneByte) { 215 if (count == buf.length) { 216 expand(1); 217 } 218 buf[count++] = (byte) oneByte; 219 } 220 221 /** 222 * Takes the contents of this stream and writes it to the output stream 223 * {@code out}. 224 * 225 * @param out 226 * an OutputStream on which to write the contents of this stream. 227 * @throws IOException 228 * if an error occurs while writing to {@code out}. 229 */ 230 public synchronized void writeTo(OutputStream out) throws IOException { 231 out.write(buf, 0, count); 232 } 233} 234