• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&quot;file.java&quot;));
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