001: /* RecyclingFastBufferedOutputStream
002: *
003: * $Id: RecyclingFastBufferedOutputStream.java 3527 2005-06-06 20:56:24Z gojomo $
004: *
005: * Created on May 26, 2005
006: *
007: * Based on FastBufferedOutputStream in MG4J; see:
008: *
009: * http://mg4j.dsi.unimi.it/
010: *
011: * (Sole addition is one new constructor.)
012: *
013: * Revisions copyright (C) 2005 Internet Archive.
014: *
015: * This file is part of the Heritrix web crawler (crawler.archive.org).
016: *
017: * Heritrix is free software; you can redistribute it and/or modify
018: * it under the terms of the GNU Lesser Public License as published by
019: * the Free Software Foundation; either version 2.1 of the License, or
020: * any later version.
021: *
022: * Heritrix is distributed in the hope that it will be useful,
023: * but WITHOUT ANY WARRANTY; without even the implied warranty of
024: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
025: * GNU Lesser Public License for more details.
026: *
027: * You should have received a copy of the GNU Lesser Public License
028: * along with Heritrix; if not, write to the Free Software
029: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
030: */
031: package org.archive.io;
032:
033: import java.io.IOException;
034: import java.io.OutputStream;
035:
036: /** Lightweight, unsynchronised, aligned output stream buffering class.
037: *
038: * <P>This class provides buffering for output streams, but it does so with
039: * purposes and an internal logic that are radically different from the ones
040: * adopted in {@link java.io.BufferedOutputStream}.
041: *
042: * <P>All methods are unsychronised. Moreover,
043: * it is guaranteed that <em>all writes performed by this class will be
044: * multiples of the given buffer size</em>. If, for instance, you use the
045: * default buffer size, writes will be performed on the underlying input stream
046: * in multiples of 16384 bytes. This is very important on operating systems
047: * that optimise disk reads on disk block boundaries.
048: */
049:
050: public class RecyclingFastBufferedOutputStream extends OutputStream {
051:
052: /** The default size of the internal buffer in bytes (16Ki). */
053: public final static int DEFAULT_BUFFER_SIZE = 16 * 1024;
054:
055: /** The internal buffer. */
056: protected byte buffer[];
057:
058: /** The current position in the buffer. */
059: protected int pos;
060:
061: /** The number of buffer bytes available starting from {@link #pos}. */
062: protected int avail;
063:
064: /** The underlying output stream. */
065: protected OutputStream os;
066:
067: /** Creates a new fast buffered output stream by wrapping a given output stream, using a given buffer
068: *
069: * @param os an output stream to wrap.
070: * @param buffer buffer to use internally.
071: */
072:
073: public RecyclingFastBufferedOutputStream(final OutputStream os,
074: final byte[] buffer) {
075: this .os = os;
076: this .buffer = buffer;
077: avail = buffer.length;
078: }
079:
080: /** Creates a new fast buffered output stream by wrapping a given output stream with a given buffer size.
081: *
082: * @param os an output stream to wrap.
083: * @param bufSize the size in bytes of the internal buffer.
084: */
085:
086: public RecyclingFastBufferedOutputStream(final OutputStream os,
087: final int bufSize) {
088: this (os, new byte[bufSize]);
089: }
090:
091: /** Creates a new fast buffered ouptut stream by wrapping a given output stream with a buffer of {@link #DEFAULT_BUFFER_SIZE} bytes.
092: *
093: * @param os an output stream to wrap.
094: */
095: public RecyclingFastBufferedOutputStream(final OutputStream os) {
096: this (os, DEFAULT_BUFFER_SIZE);
097: }
098:
099: private void dumpBufferIfFull() throws IOException {
100: if (avail == 0) {
101: os.write(buffer);
102: pos = 0;
103: avail = buffer.length;
104: }
105: }
106:
107: public void write(final int b) throws IOException {
108: avail--;
109: buffer[pos++] = (byte) b;
110: dumpBufferIfFull();
111: }
112:
113: public void write(final byte b[], int offset, int length)
114: throws IOException {
115: if (length <= avail) {
116: System.arraycopy(b, offset, buffer, pos, length);
117: pos += length;
118: avail -= length;
119: dumpBufferIfFull();
120: return;
121: }
122:
123: System.arraycopy(b, offset, buffer, pos, avail);
124: os.write(buffer);
125:
126: offset += avail;
127: length -= avail;
128:
129: final int residual = length % buffer.length;
130:
131: os.write(b, offset, length - residual);
132: System.arraycopy(b, offset + length - residual, buffer, 0,
133: residual);
134: pos = residual;
135: avail = buffer.length - residual;
136: }
137:
138: public void close() throws IOException {
139: if (os == null)
140: return;
141: if (pos != 0)
142: os.write(buffer, 0, pos);
143: if (os != System.out)
144: os.close();
145: os = null;
146: buffer = null;
147: }
148:
149: }
150:
151: // Local Variables:
152: // mode: jde
153: // tab-width: 4
154: // End:
|