1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
147
148
149
150