1 package be
.nikiroo
.utils
.streams
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
5 import java
.io
.OutputStream
;
8 * A simple {@link OutputStream} that is buffered with a bytes array.
10 * It is mostly intended to be used as a base class to create new
11 * {@link OutputStream}s with special operation modes, and to give some default
16 public class BufferedOutputStream
extends OutputStream
{
17 /** The current position in the buffer. */
19 /** The index of the last usable position of the buffer. */
21 /** The buffer itself. */
22 protected byte[] buffer
;
23 /** An End-Of-File (or buffer, here) marker. */
24 protected boolean eof
;
25 /** The actual under-laying stream. */
26 protected OutputStream out
;
27 /** The number of bytes written to the under-laying stream. */
28 protected long bytesWritten
;
30 * Can bypass the flush process for big writes (will directly write to the
31 * under-laying buffer if the array to write is > the internal buffer
34 * By default, this is true.
36 protected boolean bypassFlush
= true;
38 private boolean closed
;
39 private int openCounter
;
43 * Create a new {@link BufferedInputStream} that wraps the given
44 * {@link InputStream}.
47 * the {@link OutputStream} to wrap
49 public BufferedOutputStream(OutputStream out
) {
52 this.buffer
= new byte[4096];
53 this.b1
= new byte[1];
59 public void write(int b
) throws IOException
{
65 public void write(byte[] b
) throws IOException
{
66 write(b
, 0, b
.length
);
70 public void write(byte[] source
, int sourceOffset
, int sourceLength
)
76 throw new NullPointerException();
77 } else if ((sourceOffset
< 0) || (sourceOffset
> source
.length
)
79 || ((sourceOffset
+ sourceLength
) > source
.length
)
80 || ((sourceOffset
+ sourceLength
) < 0)) {
81 throw new IndexOutOfBoundsException();
82 } else if (sourceLength
== 0) {
86 if (bypassFlush
&& sourceLength
>= buffer
.length
) {
88 * If the request length exceeds the size of the output buffer,
89 * flush the output buffer and then write the data directly. In this
90 * way buffered streams will cascade harmlessly.
93 out
.write(source
, sourceOffset
, sourceLength
);
94 bytesWritten
+= (sourceLength
- sourceOffset
);
99 while (done
< sourceLength
) {
100 if (available() <= 0) {
104 int now
= Math
.min(sourceLength
- done
, available());
105 System
.arraycopy(source
, sourceOffset
+ done
, buffer
, stop
, now
);
112 * The available space in the buffer.
114 * @return the space in bytes
116 private int available() {
121 return Math
.max(0, buffer
.length
- stop
- 1);
125 * The number of bytes written to the under-laying {@link OutputStream}.
127 * @return the number of bytes
129 public long getBytesWritten() {
134 * Return this very same {@link BufferedInputStream}, but keep a counter of
135 * how many streams were open this way. When calling
136 * {@link BufferedInputStream#close()}, decrease this counter if it is not
137 * already zero instead of actually closing the stream.
139 * You are now responsible for it — you <b>must</b> close it.
141 * This method allows you to use a wrapping stream around this one and still
142 * close the wrapping stream.
144 * @return the same stream, but you are now responsible for closing it
146 * @throws IOException
147 * in case of I/O error or if the stream is closed
149 public synchronized OutputStream
open() throws IOException
{
156 * Check that the stream was not closed, and throw an {@link IOException} if
159 * @throws IOException
162 protected void checkClose() throws IOException
{
164 throw new IOException(
165 "This BufferedInputStream was closed, you cannot use it anymore.");
170 public void flush() throws IOException
{
175 * Flush the {@link BufferedOutputStream}, write the current buffered data
176 * to (and optionally also flush) the under-laying stream.
178 * If {@link BufferedOutputStream#bypassFlush} is false, all writes to the
179 * under-laying stream are done in this method.
181 * This can be used if you want to write some data in the under-laying
182 * stream yourself (in that case, flush this {@link BufferedOutputStream}
183 * with or without flushing the under-laying stream, then you can write to
184 * the under-laying stream).
186 * @param includingSubStream
187 * also flush the under-laying stream
188 * @throws IOException
189 * in case of I/O error
191 public void flush(boolean includingSubStream
) throws IOException
{
193 out
.write(buffer
, start
, stop
- start
);
194 bytesWritten
+= (stop
- start
);
199 if (includingSubStream
) {
205 * Closes this stream and releases any system resources associated with the
208 * Including the under-laying {@link InputStream}.
210 * <b>Note:</b> if you called the {@link BufferedInputStream#open()} method
211 * prior to this one, it will just decrease the internal count of how many
212 * open streams it held and do nothing else. The stream will actually be
213 * closed when you have called {@link BufferedInputStream#close()} once more
214 * than {@link BufferedInputStream#open()}.
216 * @exception IOException
217 * in case of I/O error
220 public synchronized void close() throws IOException
{
225 * Closes this stream and releases any system resources associated with the
228 * Including the under-laying {@link InputStream} if
229 * <tt>incudingSubStream</tt> is true.
231 * You can call this method multiple times, it will not cause an
232 * {@link IOException} for subsequent calls.
234 * <b>Note:</b> if you called the {@link BufferedInputStream#open()} method
235 * prior to this one, it will just decrease the internal count of how many
236 * open streams it held and do nothing else. The stream will actually be
237 * closed when you have called {@link BufferedInputStream#close()} once more
238 * than {@link BufferedInputStream#open()}.
240 * @param includingSubStream
241 * also close the under-laying stream
243 * @exception IOException
244 * in case of I/O error
246 public synchronized void close(boolean includingSubStream
)
249 if (openCounter
> 0) {
253 flush(includingSubStream
);
254 if (includingSubStream
&& out
!= null) {