/*
* fastutil: Fast & compact type-specific collections for Java
*
* Copyright (C) 2005, 2006 Sebastiano Vigna
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*
* ImageI/O-Ext - OpenSource Java Image translation Library
* http://www.geo-solutions.it/
* http://java.net/projects/imageio-ext/
* (C) 2007 - 2009, GeoSolutions
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* either version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package it.geosolutions.io.output;
import java.io.IOException;
import java.io.OutputStream;
/**
* Lightweight, unsynchronised, aligned output stream buffering class.
*
* <P>
* This class provides buffering for output streams, but it does so with
* purposes and an internal logic that are radically different from the ones
* adopted in {@link java.io.BufferedOutputStream}.
*
* <P>
* All methods are unsychronised. Moreover, it is guaranteed that
* <em>all writes performed by this class will be
* multiples of the given buffer size</em>.
* If, for instance, you use the default buffer size, writes will be performed
* on the underlying input stream in multiples of 16384 bytes. This is very
* important on operating systems that optimise disk reads on disk block
* boundaries. If you {@link #flush()} the stream, the buffer will be emptied,
* but it will realign again as soon as possible.
*
* @since 4.4
* @author Simone Giannecchini, GeoSolutions SAS
*/
public class FastBufferedOutputStream extends OutputStream {
/** The default size of the internal buffer in bytes (8Ki). */
public final static int DEFAULT_BUFFER_SIZE = 8 * 1024;
/** The internal buffer. */
protected byte buffer[];
/** The current position in the buffer. */
protected int pos;
/**
* The number of buffer bytes available starting from {@link #pos}. Note
* that in case {@link #flush()} has been called, the number of available
* buffer bytes might be less than {@link #buffer buffer.length}−{@link #pos}.
*/
protected int avail;
/** The underlying output stream. */
protected OutputStream os;
/**
* Creates a new fast buffered output stream by wrapping a given output
* stream with a given buffer size.
*
* @param os
* an output stream to wrap.
* @param bufSize
* the size in bytes of the internal buffer.
*/
public FastBufferedOutputStream(final OutputStream os, final int bufSize) {
this.os = os;
buffer = new byte[bufSize];
avail = bufSize;
}
/**
* Creates a new fast buffered ouptut stream by wrapping a given output
* stream with a buffer of {@link #DEFAULT_BUFFER_SIZE} bytes.
*
* @param os
* an output stream to wrap.
*/
public FastBufferedOutputStream(final OutputStream os) {
this(os, DEFAULT_BUFFER_SIZE);
}
private void dumpBufferIfFull() throws IOException {
if (avail == 0) {
os.write(buffer, 0, pos);
pos = 0;
avail = buffer.length;
}
}
public void write(final int b) throws IOException {
avail--;
buffer[pos++] = (byte) b;
dumpBufferIfFull();
}
public void write(final byte b[], int offset, int length)
throws IOException {
if (length <= avail) {
System.arraycopy(b, offset, buffer, pos, length);
pos += length;
avail -= length;
dumpBufferIfFull();
return;
}
System.arraycopy(b, offset, buffer, pos, avail);
os.write(buffer, 0, pos + avail);
offset += avail;
length -= avail;
final int residual = length % buffer.length;
os.write(b, offset, length - residual);
System.arraycopy(b, offset + length - residual, buffer, 0, residual);
pos = residual;
avail = buffer.length - residual;
}
public void flush() throws IOException {
if (pos != 0)
os.write(buffer, 0, pos);
// Note that avail is unchanged, so we will realign at the next dump.
pos = 0;
os.flush();
}
public void close() throws IOException {
if (os == null)
return;
if (pos != 0)
os.write(buffer, 0, pos);
if (os != System.out)
os.close();
os = null;
buffer = null;
}
}
// Local Variables:
// mode: jde
// tab-width: 4
// End: