KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > archive > io > BufferedSeekInputStream


1 /* BufferedSeekInputStream
2 *
3 * Created on September 14, 2006
4 *
5 * Copyright (C) 2006 Internet Archive.
6 *
7 * This file is part of the Heritrix web crawler (crawler.archive.org).
8 *
9 * Heritrix is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * any later version.
13 *
14 * Heritrix is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser Public License
20 * along with Heritrix; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */

23 package org.archive.io;
24
25
26 import java.io.IOException JavaDoc;
27
28
29 /**
30  * Buffers data from some other SeekInputStream.
31  *
32  * @author pjack
33  */

34 public class BufferedSeekInputStream extends SeekInputStream {
35
36
37     /**
38      * The underlying input stream.
39      */

40     final private SeekInputStream input;
41
42
43     /**
44      * The buffered data.
45      */

46     final private byte[] buffer;
47     
48     
49     /**
50      * The maximum offset of valid data in the buffer. Usually the same
51      * as buffer.length, but may be shorter if we're in the last region
52      * of the stream.
53      */

54     private int maxOffset;
55
56
57     /**
58      * The offset of within the buffer of the next byte to read.
59      */

60     private int offset;
61
62
63     /**
64      * Constructor.
65      *
66      * @param input the underlying input stream
67      * @param capacity the size of the buffer
68      * @throws IOException if an IO occurs filling the first buffer
69      */

70     public BufferedSeekInputStream(SeekInputStream input, int capacity)
71     throws IOException JavaDoc {
72         this.input = input;
73         this.buffer = new byte[capacity];
74         buffer();
75     }
76
77     /**
78      * Fills the buffer.
79      *
80      * @throws IOException if an IO error occurs
81      */

82     private void buffer() throws IOException JavaDoc {
83         int remaining = buffer.length;
84         while (remaining > 0) {
85             int r = input.read(buffer, buffer.length - remaining, remaining);
86             if (r <= 0) {
87                 // Not enough information to fill the buffer
88
offset = 0;
89                 maxOffset = buffer.length - remaining;
90                 return;
91             }
92             remaining -= r;
93         }
94         maxOffset = buffer.length;
95         offset = 0;
96     }
97
98
99     /**
100      * Ensures that the buffer is valid.
101      *
102      * @throws IOException if an IO error occurs
103      */

104     private void ensureBuffer() throws IOException JavaDoc {
105         if (offset >= maxOffset) {
106             buffer();
107         }
108     }
109
110
111     /**
112      * Returns the number of unread bytes in the current buffer.
113      *
114      * @return the remaining bytes
115      */

116     private int remaining() {
117         return maxOffset - offset;
118     }
119
120
121     @Override JavaDoc
122     public int read() throws IOException JavaDoc {
123         ensureBuffer();
124         if (maxOffset == 0) {
125             return -1;
126         }
127         int ch = buffer[offset] & 0xFF;
128         offset++;
129         return ch;
130     }
131
132
133     @Override JavaDoc
134     public int read(byte[] buf, int ofs, int len) throws IOException JavaDoc {
135         ensureBuffer();
136         if (maxOffset == 0) {
137             return 0;
138         }
139         len = Math.min(len, remaining());
140         System.arraycopy(buffer, offset, buf, ofs, len);
141         offset += len;
142         return len;
143     }
144
145
146     @Override JavaDoc
147     public int read(byte[] buf) throws IOException JavaDoc {
148         return read(buf, 0, buf.length);
149     }
150
151
152     @Override JavaDoc
153     public long skip(long c) throws IOException JavaDoc {
154         ensureBuffer();
155         if (maxOffset == 0) {
156             return 0;
157         }
158         int count = (c > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)c;
159         int skip = Math.min(count, remaining());
160         offset += skip;
161         return skip;
162     }
163
164
165     /**
166      * Returns the stream's current position.
167      *
168      * @return the current position
169      */

170     public long position() throws IOException JavaDoc {
171         return input.position() - buffer.length + offset;
172     }
173
174
175     /**
176      * Seeks to the given position. This method avoids re-filling the buffer
177      * if at all possible.
178      *
179      * @param p the position to set
180      * @throws IOException if an IO error occurs
181      */

182     public void position(long p) throws IOException JavaDoc {
183         long blockStart = (input.position() - maxOffset)
184          / buffer.length * buffer.length;
185         long blockEnd = blockStart + maxOffset;
186         if ((p >= blockStart) && (p < blockEnd)) {
187             // Desired position is somewhere inside current buffer
188
long adj = p - blockStart;
189             offset = (int)adj;
190             return;
191         }
192         positionDirect(p);
193     }
194
195
196     /**
197      * Positions the underlying stream at the given position, then refills
198      * the buffer.
199      *
200      * @param p the position to set
201      * @throws IOException if an IO error occurs
202      */

203     private void positionDirect(long p) throws IOException JavaDoc {
204         long newBlockStart = p / buffer.length * buffer.length;
205         input.position(newBlockStart);
206         buffer();
207         offset = (int)(p % buffer.length);
208     }
209
210     /**
211      * Close the stream, including the wrapped input stream.
212      */

213     public void close() throws IOException JavaDoc {
214         super.close();
215         if(this.input!=null) {
216             this.input.close();
217         }
218     }
219
220
221 }
222
Popular Tags