< prev index next >

src/java.base/share/classes/java/io/BufferedOutputStream.java

Print this page

  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package java.io;
 27 




 28 /**
 29  * The class implements a buffered output stream. By setting up such
 30  * an output stream, an application can write bytes to the underlying
 31  * output stream without necessarily causing a call to the underlying
 32  * system for each byte written.
 33  *
 34  * @author  Arthur van Hoff
 35  * @since   1.0
 36  */
 37 public class BufferedOutputStream extends FilterOutputStream {






 38     /**
 39      * The internal buffer where data is stored.
 40      */
 41     protected byte buf[];
 42 
 43     /**
 44      * The number of valid bytes in the buffer. This value is always
 45      * in the range {@code 0} through {@code buf.length}; elements
 46      * {@code buf[0]} through {@code buf[count-1]} contain valid
 47      * byte data.
 48      */
 49     protected int count;
 50 







































 51     /**
 52      * Creates a new buffered output stream to write data to the
 53      * specified underlying output stream.
 54      *
 55      * @param   out   the underlying output stream.
 56      */
 57     public BufferedOutputStream(OutputStream out) {
 58         this(out, 8192);
 59     }
 60 
 61     /**
 62      * Creates a new buffered output stream to write data to the
 63      * specified underlying output stream with the specified buffer
 64      * size.
 65      *
 66      * @param   out    the underlying output stream.
 67      * @param   size   the buffer size.
 68      * @throws  IllegalArgumentException if size &lt;= 0.
 69      */
 70     public BufferedOutputStream(OutputStream out, int size) {
 71         super(out);
 72         if (size <= 0) {
 73             throw new IllegalArgumentException("Buffer size <= 0");
 74         }
 75         buf = new byte[size];
 76     }
 77 
 78     /** Flush the internal buffer */
 79     private void flushBuffer() throws IOException {
 80         if (count > 0) {
 81             out.write(buf, 0, count);
 82             count = 0;
 83         }
 84     }
 85 
















 86     /**
 87      * Writes the specified byte to this buffered output stream.
 88      *
 89      * @param      b   the byte to be written.
 90      * @throws     IOException  if an I/O error occurs.
 91      */
 92     @Override
 93     public synchronized void write(int b) throws IOException {
















 94         if (count >= buf.length) {
 95             flushBuffer();
 96         }
 97         buf[count++] = (byte)b;
 98     }
 99 
100     /**
101      * Writes {@code len} bytes from the specified byte array
102      * starting at offset {@code off} to this buffered output stream.
103      *
104      * <p> Ordinarily this method stores bytes from the given array into this
105      * stream's buffer, flushing the buffer to the underlying output stream as
106      * needed.  If the requested length is at least as large as this stream's
107      * buffer, however, then this method will flush the buffer and write the
108      * bytes directly to the underlying output stream.  Thus redundant
109      * {@code BufferedOutputStream}s will not copy data unnecessarily.
110      *
111      * @param      b     the data.
112      * @param      off   the start offset in the data.
113      * @param      len   the number of bytes to write.
114      * @throws     IOException  if an I/O error occurs.
115      */
116     @Override
117     public synchronized void write(byte[] b, int off, int len) throws IOException {
118         if (len >= buf.length) {
119             /* If the request length exceeds the size of the output buffer,
















120                flush the output buffer and then write the data directly.
121                In this way buffered streams will cascade harmlessly. */
122             flushBuffer();
123             out.write(b, off, len);
124             return;
125         }

126         if (len > buf.length - count) {
127             flushBuffer();
128         }
129         System.arraycopy(b, off, buf, count, len);
130         count += len;
131     }
132 
133     /**
134      * Flushes this buffered output stream. This forces any buffered
135      * output bytes to be written out to the underlying output stream.
136      *
137      * @throws     IOException  if an I/O error occurs.
138      * @see        java.io.FilterOutputStream#out
139      */
140     @Override
141     public synchronized void flush() throws IOException {















142         flushBuffer();
143         out.flush();
144     }
145 }

  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package java.io;
 27 
 28 import java.util.Arrays;
 29 import jdk.internal.misc.InternalLock;
 30 import jdk.internal.misc.VM;
 31 
 32 /**
 33  * The class implements a buffered output stream. By setting up such
 34  * an output stream, an application can write bytes to the underlying
 35  * output stream without necessarily causing a call to the underlying
 36  * system for each byte written.
 37  *
 38  * @author  Arthur van Hoff
 39  * @since   1.0
 40  */
 41 public class BufferedOutputStream extends FilterOutputStream {
 42     private static final int DEFAULT_INITIAL_BUFFER_SIZE = 512;
 43     private static final int DEFAULT_MAX_BUFFER_SIZE = 8192;
 44 
 45     // initialized to null when BufferedOutputStream is sub-classed
 46     private final InternalLock lock;
 47 
 48     /**
 49      * The internal buffer where data is stored.
 50      */
 51     protected byte buf[];
 52 
 53     /**
 54      * The number of valid bytes in the buffer. This value is always
 55      * in the range {@code 0} through {@code buf.length}; elements
 56      * {@code buf[0]} through {@code buf[count-1]} contain valid
 57      * byte data.
 58      */
 59     protected int count;
 60 
 61     /**
 62      * Max size of the internal buffer or -1 if internal buffer cannot be resized.
 63      */
 64     private final int maxBufSize;
 65 
 66     /**
 67      * Returns the buffer size to use when no output buffer size specified
 68      */
 69     private static int initialBufferSize() {
 70         if (VM.isBooted() && Thread.currentThread().isVirtual()) {
 71             return DEFAULT_INITIAL_BUFFER_SIZE;
 72         } else {
 73             return DEFAULT_MAX_BUFFER_SIZE;
 74         }
 75     }
 76 
 77     /**
 78      * Creates a new buffered output stream.
 79      */
 80     private BufferedOutputStream(OutputStream out, int initialSize, int maxSize) {
 81         super(out);
 82 
 83         if (initialSize <= 0) {
 84             throw new IllegalArgumentException("Buffer size <= 0");
 85         }
 86 
 87         if (getClass() == BufferedOutputStream.class) {
 88             // use InternalLock and resizable buffer when not sub-classed
 89             this.lock = new InternalLock();
 90             this.buf = new byte[initialSize];    // resizable
 91             this.maxBufSize = maxSize;
 92         } else {
 93             // use monitors and no resizing when sub-classed
 94             this.lock = null;
 95             this.buf = new byte[maxSize];
 96             this.maxBufSize = -1;
 97         }
 98     }
 99 
100     /**
101      * Creates a new buffered output stream to write data to the
102      * specified underlying output stream.
103      *
104      * @param   out   the underlying output stream.
105      */
106     public BufferedOutputStream(OutputStream out) {
107         this(out, initialBufferSize(), DEFAULT_MAX_BUFFER_SIZE);
108     }
109 
110     /**
111      * Creates a new buffered output stream to write data to the
112      * specified underlying output stream with the specified buffer
113      * size.
114      *
115      * @param   out    the underlying output stream.
116      * @param   size   the buffer size.
117      * @throws  IllegalArgumentException if size &lt;= 0.
118      */
119     public BufferedOutputStream(OutputStream out, int size) {
120         this(out, size, size);




121     }
122 
123     /** Flush the internal buffer */
124     private void flushBuffer() throws IOException {
125         if (count > 0) {
126             out.write(buf, 0, count);
127             count = 0;
128         }
129     }
130 
131     /**
132      * Grow buf to fit an additional len bytes if needed.
133      * If possible, it grows by len+1 to avoid flushing when len bytes
134      * are added. A no-op if the buffer is not resizable.
135      */
136     private void growIfNeeded(int len) {
137         if (maxBufSize > 0) {
138             int neededSize = count + len + 1;
139             int bufSize = buf.length;
140             if (neededSize > bufSize && bufSize < maxBufSize) {
141                 int newSize = Math.min(neededSize, maxBufSize);
142                 buf = Arrays.copyOf(buf, newSize);
143             }
144         }
145     }
146 
147     /**
148      * Writes the specified byte to this buffered output stream.
149      *
150      * @param      b   the byte to be written.
151      * @throws     IOException  if an I/O error occurs.
152      */
153     @Override
154     public void write(int b) throws IOException {
155         if (lock != null) {
156             lock.lock();
157             try {
158                 lockedWrite(b);
159             } finally {
160                 lock.unlock();
161             }
162         } else {
163             synchronized (this) {
164                 lockedWrite(b);
165             }
166         }
167     }
168 
169     private void lockedWrite(int b) throws IOException {
170         growIfNeeded(1);
171         if (count >= buf.length) {
172             flushBuffer();
173         }
174         buf[count++] = (byte)b;
175     }
176 
177     /**
178      * Writes {@code len} bytes from the specified byte array
179      * starting at offset {@code off} to this buffered output stream.
180      *
181      * <p> Ordinarily this method stores bytes from the given array into this
182      * stream's buffer, flushing the buffer to the underlying output stream as
183      * needed.  If the requested length is at least as large as this stream's
184      * buffer, however, then this method will flush the buffer and write the
185      * bytes directly to the underlying output stream.  Thus redundant
186      * {@code BufferedOutputStream}s will not copy data unnecessarily.
187      *
188      * @param      b     the data.
189      * @param      off   the start offset in the data.
190      * @param      len   the number of bytes to write.
191      * @throws     IOException  if an I/O error occurs.
192      */
193     @Override
194     public void write(byte[] b, int off, int len) throws IOException {
195         if (lock != null) {
196             lock.lock();
197             try {
198                 lockedWrite(b, off, len);
199             } finally {
200                 lock.unlock();
201             }
202         } else {
203             synchronized (this) {
204                 lockedWrite(b, off, len);
205             }
206         }
207     }
208 
209     private void lockedWrite(byte[] b, int off, int len) throws IOException {
210         int max = (maxBufSize > 0) ? maxBufSize : buf.length;
211         if (len >= max) {
212             /* If the request length exceeds the max size of the output buffer,
213                flush the output buffer and then write the data directly.
214                In this way buffered streams will cascade harmlessly. */
215             flushBuffer();
216             out.write(b, off, len);
217             return;
218         }
219         growIfNeeded(len);
220         if (len > buf.length - count) {
221             flushBuffer();
222         }
223         System.arraycopy(b, off, buf, count, len);
224         count += len;
225     }
226 
227     /**
228      * Flushes this buffered output stream. This forces any buffered
229      * output bytes to be written out to the underlying output stream.
230      *
231      * @throws     IOException  if an I/O error occurs.
232      * @see        java.io.FilterOutputStream#out
233      */
234     @Override
235     public void flush() throws IOException {
236         if (lock != null) {
237             lock.lock();
238             try {
239                 lockedFlush();
240             } finally {
241                 lock.unlock();
242             }
243         } else {
244             synchronized (this) {
245                 lockedFlush();
246             }
247         }
248     }
249 
250     private void lockedFlush() throws IOException {
251         flushBuffer();
252         out.flush();
253     }
254 }
< prev index next >