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 18 package java.io; 19 20 import java.util.Arrays; 21 22 /** 23 * Wraps an existing {@link OutputStream} and <em>buffers</em> the output. 24 * Expensive interaction with the underlying input stream is minimized, since 25 * most (smaller) requests can be satisfied by accessing the buffer alone. The 26 * drawback is that some extra space is required to hold the buffer and that 27 * copying takes place when flushing that buffer, but this is usually outweighed 28 * by the performance benefits. 29 * 30 * <p/>A typical application pattern for the class looks like this:<p/> 31 * 32 * <pre> 33 * BufferedOutputStream buf = new BufferedOutputStream(new FileOutputStream("file.java")); 34 * </pre> 35 * 36 * @see BufferedInputStream 37 */ 38 public class BufferedOutputStream extends FilterOutputStream { 39 /** 40 * The buffer containing the bytes to be written to the target stream. 41 */ 42 protected byte[] buf; 43 44 /** 45 * The total number of bytes inside the byte array {@code buf}. 46 */ 47 protected int count; 48 49 /** 50 * Constructs a new {@code BufferedOutputStream}, providing {@code out} with a buffer 51 * of 8192 bytes. 52 * 53 * @param out the {@code OutputStream} the buffer writes to. 54 */ BufferedOutputStream(OutputStream out)55 public BufferedOutputStream(OutputStream out) { 56 this(out, 8192); 57 } 58 59 /** 60 * Constructs a new {@code BufferedOutputStream}, providing {@code out} with {@code size} bytes 61 * of buffer. 62 * 63 * @param out the {@code OutputStream} the buffer writes to. 64 * @param size the size of buffer in bytes. 65 * @throws IllegalArgumentException if {@code size <= 0}. 66 */ BufferedOutputStream(OutputStream out, int size)67 public BufferedOutputStream(OutputStream out, int size) { 68 super(out); 69 if (size <= 0) { 70 throw new IllegalArgumentException("size <= 0"); 71 } 72 buf = new byte[size]; 73 } 74 75 /** 76 * Flushes this stream to ensure all pending data is written out to the 77 * target stream. In addition, the target stream is flushed. 78 * 79 * @throws IOException 80 * if an error occurs attempting to flush this stream. 81 */ 82 @Override flush()83 public synchronized void flush() throws IOException { 84 checkNotClosed(); 85 flushInternal(); 86 out.flush(); 87 } 88 checkNotClosed()89 private void checkNotClosed() throws IOException { 90 if (buf == null) { 91 throw new IOException("BufferedOutputStream is closed"); 92 } 93 } 94 95 /** 96 * Writes {@code count} bytes from the byte array {@code buffer} starting at 97 * {@code offset} to this stream. If there is room in the buffer to hold the 98 * bytes, they are copied in. If not, the buffered bytes plus the bytes in 99 * {@code buffer} are written to the target stream, the target is flushed, 100 * and the buffer is cleared. 101 * 102 * @param buffer 103 * the buffer to be written. 104 * @param offset 105 * the start position in {@code buffer} from where to get bytes. 106 * @param length 107 * the number of bytes from {@code buffer} to write to this 108 * stream. 109 * @throws IndexOutOfBoundsException 110 * if {@code offset < 0} or {@code length < 0}, or if 111 * {@code offset + length} is greater than the size of 112 * {@code buffer}. 113 * @throws IOException 114 * if an error occurs attempting to write to this stream. 115 * @throws NullPointerException 116 * if {@code buffer} is {@code null}. 117 * @throws ArrayIndexOutOfBoundsException 118 * If offset or count is outside of bounds. 119 */ 120 @Override write(byte[] buffer, int offset, int length)121 public synchronized void write(byte[] buffer, int offset, int length) throws IOException { 122 checkNotClosed(); 123 124 if (buffer == null) { 125 throw new NullPointerException("buffer == null"); 126 } 127 128 byte[] internalBuffer = buf; 129 if (length >= internalBuffer.length) { 130 flushInternal(); 131 out.write(buffer, offset, length); 132 return; 133 } 134 135 Arrays.checkOffsetAndCount(buffer.length, offset, length); 136 137 // flush the internal buffer first if we have not enough space left 138 if (length > (internalBuffer.length - count)) { 139 flushInternal(); 140 } 141 142 System.arraycopy(buffer, offset, internalBuffer, count, length); 143 count += length; 144 } 145 close()146 @Override public synchronized void close() throws IOException { 147 if (buf == null) { 148 return; 149 } 150 151 try { 152 super.close(); 153 } finally { 154 buf = null; 155 } 156 } 157 158 /** 159 * Writes one byte to this stream. Only the low order byte of the integer 160 * {@code oneByte} is written. If there is room in the buffer, the byte is 161 * copied into the buffer and the count incremented. Otherwise, the buffer 162 * plus {@code oneByte} are written to the target stream, the target is 163 * flushed, and the buffer is reset. 164 * 165 * @param oneByte 166 * the byte to be written. 167 * @throws IOException 168 * if an error occurs attempting to write to this stream. 169 */ 170 @Override write(int oneByte)171 public synchronized void write(int oneByte) throws IOException { 172 checkNotClosed(); 173 if (count == buf.length) { 174 out.write(buf, 0, count); 175 count = 0; 176 } 177 buf[count++] = (byte) oneByte; 178 } 179 180 /** 181 * Flushes only internal buffer. 182 */ flushInternal()183 private void flushInternal() throws IOException { 184 if (count > 0) { 185 out.write(buf, 0, count); 186 count = 0; 187 } 188 } 189 } 190