BufferedOutputStream.java revision a0881d052ee72e3f7e773374e9b1aa75fbd6be4c
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 org.apache.harmony.luni.util.Msg; 21 22// BEGIN android-added 23import java.util.logging.Logger; 24// END android-added 25 26/** 27 * Wraps an existing {@link OutputStream} and <em>buffers</em> the output. 28 * Expensive interaction with the underlying input stream is minimized, since 29 * most (smaller) requests can be satisfied by accessing the buffer alone. The 30 * drawback is that some extra space is required to hold the buffer and that 31 * copying takes place when flushing that buffer, but this is usually outweighed 32 * by the performance benefits. 33 * 34 * <p/>A typical application pattern for the class looks like this:<p/> 35 * 36 * <pre> 37 * BufferedOutputStream buf = new BufferedOutputStream(new FileOutputStream("file.java")); 38 * </pre> 39 * 40 * @see BufferedInputStream 41 * 42 * @since Android 1.0 43 */ 44public class BufferedOutputStream extends FilterOutputStream { 45 /** 46 * The buffer containing the bytes to be written to the target stream. 47 * 48 * @since Android 1.0 49 */ 50 protected byte[] buf; 51 52 /** 53 * The total number of bytes inside the byte array {@code buf}. 54 * 55 * @since Android 1.0 56 */ 57 protected int count; 58 59 /** 60 * Constructs a new {@code BufferedOutputStream} on the {@link OutputStream} 61 * {@code out}. The buffer size is set to the default value of 8 KB. 62 * 63 * @param out 64 * the {@code OutputStream} for which write operations are 65 * buffered. 66 * @since Android 1.0 67 */ 68 public BufferedOutputStream(OutputStream out) { 69 super(out); 70 buf = new byte[8192]; 71 72 // BEGIN android-added 73 /* 74 * For Android, we want to discourage the use of this constructor (with 75 * its arguably too-large default), so we note its use in the log. We 76 * don't disable it, nor do we alter the default, however, because we 77 * still aim to behave compatibly, and the default value, though not 78 * documented, is established by convention. 79 */ 80 Logger.global.info( 81 "Default buffer size used in BufferedOutputStream " + 82 "constructor. It would be " + 83 "better to be explicit if a 8k buffer is required."); 84 // END android-added 85 } 86 87 /** 88 * Constructs a new {@code BufferedOutputStream} on the {@link OutputStream} 89 * {@code out}. The buffer size is set to {@code size}. 90 * 91 * @param out 92 * the output stream for which write operations are buffered. 93 * @param size 94 * the size of the buffer in bytes. 95 * @throws IllegalArgumentException 96 * if {@code size <= 0}. 97 * @since Android 1.0 98 */ 99 public BufferedOutputStream(OutputStream out, int size) { 100 super(out); 101 if (size <= 0) { 102 // K0058=size must be > 0 103 throw new IllegalArgumentException(Msg.getString("K0058")); //$NON-NLS-1$ 104 } 105 buf = new byte[size]; 106 } 107 108 /** 109 * Flushes this stream to ensure all pending data is written out to the 110 * target stream. In addition, the target stream is flushed. 111 * 112 * @throws IOException 113 * if an error occurs attempting to flush this stream. 114 * @since Android 1.0 115 */ 116 @Override 117 public synchronized void flush() throws IOException { 118 if (count > 0) { 119 out.write(buf, 0, count); 120 } 121 count = 0; 122 out.flush(); 123 } 124 125 /** 126 * Writes {@code count} bytes from the byte array {@code buffer} starting at 127 * {@code offset} to this stream. If there is room in the buffer to hold the 128 * bytes, they are copied in. If not, the buffered bytes plus the bytes in 129 * {@code buffer} are written to the target stream, the target is flushed, 130 * and the buffer is cleared. 131 * 132 * @param buffer 133 * the buffer to be written. 134 * @param offset 135 * the start position in {@code buffer} from where to get bytes. 136 * @param length 137 * the number of bytes from {@code buffer} to write to this 138 * stream. 139 * @throws IndexOutOfBoundsException 140 * if {@code offset < 0} or {@code length < 0}, or if 141 * {@code offset + length} is greater than the size of 142 * {@code buffer}. 143 * @throws IOException 144 * if an error occurs attempting to write to this stream. 145 * @throws NullPointerException 146 * if {@code buffer} is {@code null}. 147 * @since Android 1.0 148 */ 149 @Override 150 public synchronized void write(byte[] buffer, int offset, int length) 151 throws IOException { 152 if (buffer == null) { 153 // K0047=buffer is null 154 throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$ 155 } 156 // BEGIN android-changed 157 // Exception priorities (in case of multiple errors) differ from 158 // RI, but are spec-compliant. 159 // used (offset | length) < 0 instead of (offset < 0) || (length < 0) 160 // to safe one operation 161 if ((offset | length) < 0 || offset > buffer.length - length) { 162 // K002f=Arguments out of bounds 163 throw new ArrayIndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$ 164 } 165 // END android-changed 166 if (count == 0 && length >= buf.length) { 167 out.write(buffer, offset, length); 168 return; 169 } 170 int available = buf.length - count; 171 if (length < available) { 172 available = length; 173 } 174 if (available > 0) { 175 System.arraycopy(buffer, offset, buf, count, available); 176 count += available; 177 } 178 if (count == buf.length) { 179 out.write(buf, 0, buf.length); 180 count = 0; 181 if (length > available) { 182 offset += available; 183 available = length - available; 184 if (available >= buf.length) { 185 out.write(buffer, offset, available); 186 } else { 187 System.arraycopy(buffer, offset, buf, count, available); 188 count += available; 189 } 190 } 191 } 192 } 193 194 /** 195 * Writes one byte to this stream. Only the low order byte of the integer 196 * {@code oneByte} is written. If there is room in the buffer, the byte is 197 * copied into the buffer and the count incremented. Otherwise, the buffer 198 * plus {@code oneByte} are written to the target stream, the target is 199 * flushed, and the buffer is reset. 200 * 201 * @param oneByte 202 * the byte to be written. 203 * @throws IOException 204 * if an error occurs attempting to write to this stream. 205 * @since Android 1.0 206 */ 207 @Override 208 public synchronized void write(int oneByte) throws IOException { 209 if (count == buf.length) { 210 out.write(buf, 0, count); 211 count = 0; 212 } 213 buf[count++] = (byte) oneByte; 214 } 215} 216