001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.io;
019:
020: import org.apache.harmony.luni.util.Msg;
021:
022: /**
023: * BufferedOutputStream is a class which takes an output stream and
024: * <em>buffers</em> the writes to that stream. In this way, costly interaction
025: * with the original output stream can be minimized by writing buffered amounts
026: * of data infrequently. The drawback is that extra space is required to hold
027: * the buffer and copying takes place when writing that buffer.
028: *
029: * @see BufferedInputStream
030: */
031: public class BufferedOutputStream extends FilterOutputStream {
032: /**
033: * The buffer containing the bytes to be written to the target OutputStream.
034: */
035: protected byte[] buf;
036:
037: /**
038: * The total number of bytes inside the byte array <code>buf</code>.
039: */
040: protected int count;
041:
042: /**
043: * Constructs a new BufferedOutputStream on the OutputStream
044: * <code>out</code>. The default buffer size (8Kb) is allocated and all
045: * writes are now filtered through this stream.
046: *
047: * @param out
048: * the OutputStream to buffer writes on.
049: */
050: public BufferedOutputStream(OutputStream out) {
051: super (out);
052: buf = new byte[8192];
053: }
054:
055: /**
056: * Constructs a new BufferedOutputStream on the OutputStream
057: * <code>out</code>. The buffer size is set to <code>size</code> and
058: * all writes are now filtered through this stream.
059: *
060: * @param out
061: * the OutputStream to buffer writes on.
062: * @param size
063: * the size of the buffer in bytes.
064: * @throws IllegalArgumentException
065: * the size is <= 0
066: */
067: public BufferedOutputStream(OutputStream out, int size) {
068: super (out);
069: if (size <= 0) {
070: // K0058=size must be > 0
071: throw new IllegalArgumentException(Msg.getString("K0058")); //$NON-NLS-1$
072: }
073: buf = new byte[size];
074: }
075:
076: /**
077: * Flush this BufferedOutputStream to ensure all pending data is written out
078: * to the target OutputStream. In addition, the target stream is also
079: * flushed.
080: *
081: * @throws IOException
082: * If an error occurs attempting to flush this
083: * BufferedOutputStream.
084: */
085: @Override
086: public synchronized void flush() throws IOException {
087: flushInternal();
088: out.flush();
089: }
090:
091: /**
092: * Writes <code>count</code> <code>bytes</code> from the byte array
093: * <code>buffer</code> starting at <code>offset</code> to this
094: * BufferedOutputStream. If there is room in the buffer to hold the bytes,
095: * they are copied in. If not, the buffered bytes plus the bytes in
096: * <code>buffer</code> are written to the target stream, the target is
097: * flushed, and the buffer is cleared.
098: *
099: * @param buffer
100: * the buffer to be written
101: * @param offset
102: * offset in buffer to get bytes
103: * @param length
104: * number of bytes in buffer to write
105: *
106: * @throws IOException
107: * If an error occurs attempting to write to this
108: * BufferedOutputStream.
109: * @throws NullPointerException
110: * If buffer is null.
111: * @throws ArrayIndexOutOfBoundsException
112: * If offset or count is outside of bounds.
113: */
114: @Override
115: public synchronized void write(byte[] buffer, int offset, int length)
116: throws IOException {
117: if (buffer == null) {
118: // K0047=buffer is null
119: throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$
120: }
121:
122: if (length >= buf.length) {
123: flushInternal();
124: out.write(buffer, offset, length);
125: return;
126: }
127:
128: if (offset < 0 || offset > buffer.length - length || length < 0) {
129: // K002f=Arguments out of bounds
130: throw new ArrayIndexOutOfBoundsException(Msg
131: .getString("K002f")); //$NON-NLS-1$
132: }
133:
134: // flush the internal buffer first if we have not enough space left
135: if (length >= (buf.length - count)) {
136: flushInternal();
137: }
138:
139: // the length is always less than (buf.length - count) here so arraycopy is safe
140: System.arraycopy(buffer, offset, buf, count, length);
141: count += length;
142: }
143:
144: /**
145: * Writes the specified byte <code>oneByte</code> to this
146: * BufferedOutputStream. Only the low order byte of <code>oneByte</code>
147: * is written. If there is room in the buffer, the byte is copied in and the
148: * count incremented. Otherwise, the buffer plus <code>oneByte</code> are
149: * written to the target stream, the target is flushed, and the buffer is
150: * reset.
151: *
152: * @param oneByte
153: * the byte to be written
154: *
155: * @throws IOException
156: * If an error occurs attempting to write to this
157: * BufferedOutputStream.
158: */
159: @Override
160: public synchronized void write(int oneByte) throws IOException {
161: if (count == buf.length) {
162: out.write(buf, 0, count);
163: count = 0;
164: }
165: buf[count++] = (byte) oneByte;
166: }
167:
168: /**
169: * Flushes only internal buffer.
170: */
171: private void flushInternal() throws IOException {
172: if (count > 0) {
173: out.write(buf, 0, count);
174: }
175: count = 0;
176: }
177: }
|