View Javadoc

1   /* RecyclingFastBufferedOutputStream
2   *
3   * $Id: RecyclingFastBufferedOutputStream.java 3527 2005-06-06 20:56:24Z gojomo $
4   *
5   * Created on May 26, 2005
6   *
7   * Based on FastBufferedOutputStream in MG4J; see:
8   * 
9   *   http://mg4j.dsi.unimi.it/
10  * 
11  * (Sole addition is one new constructor.)
12  *  
13  * Revisions copyright (C) 2005 Internet Archive.
14  *
15  * This file is part of the Heritrix web crawler (crawler.archive.org).
16  *
17  * Heritrix is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU Lesser Public License as published by
19  * the Free Software Foundation; either version 2.1 of the License, or
20  * any later version.
21  *
22  * Heritrix is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU Lesser Public License for more details.
26  *
27  * You should have received a copy of the GNU Lesser Public License
28  * along with Heritrix; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30  */ 
31  package org.archive.io;
32  
33  import java.io.IOException;
34  import java.io.OutputStream;
35  
36  /*** Lightweight, unsynchronised, aligned output stream buffering class.
37   *
38   * <P>This class provides buffering for output streams, but it does so with 
39   * purposes and an internal logic that are radically different from the ones
40   * adopted in {@link java.io.BufferedOutputStream}.
41   * 
42   * <P>All methods are unsychronised. Moreover,
43   * it is guaranteed that <em>all writes performed by this class will be
44   * multiples of the given buffer size</em>.  If, for instance, you use the
45   * default buffer size, writes will be performed on the underlying input stream
46   * in multiples of 16384 bytes. This is very important on operating systems
47   * that optimise disk reads on disk block boundaries.
48   */
49  
50  public class RecyclingFastBufferedOutputStream extends OutputStream {
51  
52      /*** The default size of the internal buffer in bytes (16Ki). */
53      public final static int DEFAULT_BUFFER_SIZE = 16 * 1024;
54  
55      /*** The internal buffer. */
56      protected byte buffer[];
57  
58      /*** The current position in the buffer. */
59      protected int pos;
60  
61      /*** The number of buffer bytes available starting from {@link #pos}. */
62      protected int avail;
63  
64      /*** The underlying output stream. */
65      protected OutputStream os;
66  
67      /*** Creates a new fast buffered output stream by wrapping a given output stream, using a given buffer 
68      *
69      * @param os an output stream to wrap.
70      * @param buffer buffer to use internally.
71      */
72  
73     public RecyclingFastBufferedOutputStream( final OutputStream os, final byte[] buffer ) {
74         this.os = os;
75         this.buffer = buffer;
76         avail = buffer.length;
77     }
78     
79      /*** Creates a new fast buffered output stream by wrapping a given output stream with a given buffer size. 
80       *
81       * @param os an output stream to wrap.
82       * @param bufSize the size in bytes of the internal buffer.
83       */
84  
85      public RecyclingFastBufferedOutputStream( final OutputStream os, final int bufSize ) {
86          this(os, new byte [ bufSize]);
87      }
88  
89      /*** Creates a new fast buffered ouptut stream by wrapping a given output stream with a buffer of {@link #DEFAULT_BUFFER_SIZE} bytes. 
90       *
91       * @param os an output stream to wrap.
92       */
93      public RecyclingFastBufferedOutputStream( final OutputStream os ) {
94          this( os, DEFAULT_BUFFER_SIZE );
95      }
96  
97      private void dumpBufferIfFull() throws IOException {
98          if ( avail == 0 ) {
99              os.write( buffer );
100             pos = 0;
101             avail = buffer.length;
102         }
103     }
104 
105     public void write( final int b ) throws IOException {
106         avail--;
107         buffer[ pos++ ] = (byte)b;
108         dumpBufferIfFull();
109     }
110 
111 
112     public void write( final byte b[], int offset, int length ) throws IOException {
113         if ( length <= avail ) {
114             System.arraycopy( b, offset, buffer, pos, length );
115             pos += length;
116             avail -= length;
117             dumpBufferIfFull();
118             return;
119         }
120     
121         System.arraycopy( b, offset, buffer, pos, avail );
122         os.write( buffer );
123 
124         offset += avail;
125         length -= avail;
126 
127         final int residual = length % buffer.length;
128 
129         os.write( b, offset, length - residual ); 
130         System.arraycopy( b, offset + length - residual, buffer, 0, residual );
131         pos = residual;
132         avail = buffer.length - residual;
133     }
134 
135     public void close() throws IOException {
136         if ( os == null ) return;
137         if ( pos != 0 ) os.write( buffer, 0, pos );
138         if ( os != System.out ) os.close();
139         os = null;
140         buffer = null;
141     }
142 
143 }
144     
145 
146 // Local Variables:
147 // mode: jde
148 // tab-width: 4
149 // End:
150