Revision | 846f4eb85573a90e025ff125142b111d3fc08361 (tree) |
---|---|
Zeit | 2022-04-16 20:52:36 |
Autor | Hiroshi Miura <miurahr@linu...> |
Commiter | GitHub |
RandomAccessInputStream: Support java.nio.channels.FileChannel (#49)
* RAIS: Support java.nio.channels.FileChannel
Signed-off-by: Hiroshi Miura <miurahr@linux.com>
@@ -25,6 +25,8 @@ import org.jetbrains.annotations.NotNull; | ||
25 | 25 | import java.io.IOException; |
26 | 26 | import java.io.InputStream; |
27 | 27 | import java.io.RandomAccessFile; |
28 | +import java.nio.ByteBuffer; | |
29 | +import java.nio.channels.FileChannel; | |
28 | 30 | |
29 | 31 | /** |
30 | 32 | * RandomAccessInputStream. |
@@ -36,24 +38,26 @@ import java.io.RandomAccessFile; | ||
36 | 38 | public class RandomAccessInputStream extends InputStream { |
37 | 39 | private static final int DEFAULT_BUFSIZE = 4096; |
38 | 40 | private final RandomAccessFile in; |
39 | - private final byte[] inbuf; | |
41 | + private final ByteBuffer byteBuffer; | |
40 | 42 | private final int bufsize; |
41 | 43 | |
42 | 44 | private long currentpos = 0; |
43 | 45 | private long startpos = -1; |
44 | 46 | private long endpos = -1; |
45 | 47 | private long mark = 0; |
48 | + private FileChannel fileChannel; | |
46 | 49 | |
47 | 50 | |
48 | 51 | /** |
49 | 52 | * Constructor of RandomAccessInputStream, accept RandomAccessFile and buffer size. |
50 | - * @param inFile RandomAccessFile file. | |
51 | - * @param bufsize buffer size. | |
53 | + * @param inFile RandomAccessFile | |
54 | + * @param bufsize buffer size | |
52 | 55 | */ |
53 | 56 | public RandomAccessInputStream(final RandomAccessFile inFile, final int bufsize) { |
54 | - this.in = inFile; | |
57 | + in = inFile; | |
55 | 58 | this.bufsize = bufsize; |
56 | - inbuf = new byte[bufsize]; | |
59 | + fileChannel = inFile.getChannel(); | |
60 | + byteBuffer = ByteBuffer.allocate(bufsize); | |
57 | 61 | } |
58 | 62 | |
59 | 63 | /** |
@@ -77,6 +81,14 @@ public class RandomAccessInputStream extends InputStream { | ||
77 | 81 | } |
78 | 82 | |
79 | 83 | /** |
84 | + * Get an unique FileChannel Object related to the file. | |
85 | + * @return FileChannel object. | |
86 | + */ | |
87 | + public final FileChannel getChannel() { | |
88 | + return fileChannel; | |
89 | + } | |
90 | + | |
91 | + /** | |
80 | 92 | * {@inheritDoc} |
81 | 93 | */ |
82 | 94 | @Override |
@@ -94,6 +106,7 @@ public class RandomAccessInputStream extends InputStream { | ||
94 | 106 | @Override |
95 | 107 | public final void close() throws IOException { |
96 | 108 | in.close(); |
109 | + fileChannel = null; | |
97 | 110 | } |
98 | 111 | |
99 | 112 | /** |
@@ -103,7 +116,7 @@ public class RandomAccessInputStream extends InputStream { | ||
103 | 116 | * @exception IOException if an I/O error has occurred. |
104 | 117 | */ |
105 | 118 | public final long length() throws IOException { |
106 | - return in.length(); | |
119 | + return fileChannel.size(); | |
107 | 120 | } |
108 | 121 | |
109 | 122 | public final int getLength() throws IOException { |
@@ -162,23 +175,25 @@ public class RandomAccessInputStream extends InputStream { | ||
162 | 175 | * @param pos position to read. |
163 | 176 | * @return -1 when position is greater than the file's current size, otherwise byte value. |
164 | 177 | */ |
165 | - public int read(long pos) { | |
178 | + public synchronized int read(long pos) { | |
166 | 179 | if (pos < startpos || pos > endpos) { |
167 | 180 | long blockstart = (pos/ bufsize) * bufsize; |
168 | - int n; | |
181 | + int n = 0; | |
169 | 182 | try { |
170 | - in.seek(blockstart); | |
171 | - n = in.read(inbuf); | |
183 | + fileChannel.position(blockstart); | |
184 | + byteBuffer.clear(); | |
185 | + n += fileChannel.read(byteBuffer); | |
172 | 186 | } catch (IOException e) { |
173 | 187 | return -1; |
174 | 188 | } |
189 | + byteBuffer.flip(); | |
175 | 190 | startpos = blockstart; |
176 | 191 | endpos = blockstart + n - 1; |
177 | 192 | if (pos < startpos || pos > endpos) { |
178 | 193 | return -1; |
179 | 194 | } |
180 | 195 | } |
181 | - return inbuf[(int) (pos - startpos)] & 0xff; | |
196 | + return byteBuffer.get((int) (pos - startpos)) & 0xff; | |
182 | 197 | } |
183 | 198 | |
184 | 199 | /** |
@@ -186,17 +201,27 @@ public class RandomAccessInputStream extends InputStream { | ||
186 | 201 | */ |
187 | 202 | @Override |
188 | 203 | public final int read(final byte @NotNull [] buf, final int off, final int len) throws IOException { |
189 | - int idx = 0; | |
190 | - while (idx < len) { | |
191 | - int c = read(currentpos); | |
192 | - if (c == -1) { | |
193 | - return idx; | |
194 | - } else { | |
195 | - buf[off + idx++] = (byte) c; | |
196 | - currentpos++; | |
204 | + if (currentpos < startpos || currentpos > endpos) { | |
205 | + long blockstart = (currentpos / bufsize) * bufsize; | |
206 | + long n = 0; | |
207 | + try { | |
208 | + fileChannel.position(blockstart); | |
209 | + byteBuffer.clear(); | |
210 | + n += fileChannel.read(byteBuffer); | |
211 | + } catch (IOException e) { | |
212 | + return -1; | |
213 | + } | |
214 | + startpos = blockstart; | |
215 | + endpos = blockstart + n - 1; | |
216 | + if (currentpos < startpos || currentpos > endpos) { | |
217 | + return -1; | |
197 | 218 | } |
198 | 219 | } |
199 | - return idx; | |
220 | + byteBuffer.position((int) (currentpos - startpos)); | |
221 | + int size = Math.min(Math.min(len, (int)(length() - currentpos)), byteBuffer.remaining()); | |
222 | + byteBuffer.get(buf, off, size); | |
223 | + currentpos += size; | |
224 | + return size; | |
200 | 225 | } |
201 | 226 | |
202 | 227 | /** |
@@ -206,14 +231,9 @@ public class RandomAccessInputStream extends InputStream { | ||
206 | 231 | * @exception IOException if an I/O error has occurred. |
207 | 232 | */ |
208 | 233 | public final void readFully(final byte[] buf) throws IOException { |
209 | - int idx = 0; | |
210 | - while (idx < buf.length) { | |
211 | - int c = read(currentpos); | |
212 | - if (c == -1) { | |
213 | - throw new IOException(); | |
214 | - } | |
215 | - buf[idx++] = (byte) c; | |
216 | - currentpos++; | |
234 | + int offset = read(buf, 0, buf.length); | |
235 | + while (offset < buf.length) { | |
236 | + offset += read(buf, offset, buf.length - offset); | |
217 | 237 | } |
218 | 238 | } |
219 | 239 |
@@ -221,7 +241,7 @@ public class RandomAccessInputStream extends InputStream { | ||
221 | 241 | * {@inheritDoc} |
222 | 242 | */ |
223 | 243 | @Override |
224 | - public final synchronized void reset() throws IOException { | |
244 | + public final synchronized void reset() { | |
225 | 245 | currentpos = mark; |
226 | 246 | } |
227 | 247 |
@@ -231,7 +251,6 @@ public class RandomAccessInputStream extends InputStream { | ||
231 | 251 | * when specified position is beyond of end of the file, position is set to end of file. |
232 | 252 | * |
233 | 253 | * @param pos file position in byte. |
234 | - * @exception IOException if an I/O error has occurred. | |
235 | 254 | */ |
236 | 255 | public final void seek(final long pos) throws IOException { |
237 | 256 | if (pos < 0) { |
@@ -268,8 +268,8 @@ public class DictZipInputStreamTest { | ||
268 | 268 | } |
269 | 269 | // read trailer |
270 | 270 | din.readTrailer(); |
271 | - assertEquals(din.getCrc(), 0x024d1f37); | |
272 | - assertEquals(din.getLength(), 383783); | |
271 | + assertEquals(0x024d1f37, din.getCrc()); | |
272 | + assertEquals(383783, din.getLength()); | |
273 | 273 | } |
274 | 274 | } |
275 | 275 |
@@ -219,14 +219,16 @@ public class RandomAccessInputStreamTest { | ||
219 | 219 | |
220 | 220 | @Test |
221 | 221 | public void testLastBytes() throws Exception { |
222 | - RandomAccessInputStream instance = new RandomAccessInputStream(dataFile, "r"); | |
223 | - instance.seek(136848); | |
224 | - byte[] buf = new byte[9]; | |
225 | - int len = instance.read(buf, 0, buf.length); | |
226 | - assertEquals(8, len); | |
227 | - assertEquals(5, buf[len - 2]); | |
228 | - assertEquals(0, buf[len - 1]); | |
229 | - long pos = instance.position(); | |
222 | + long pos; | |
223 | + try (RandomAccessInputStream instance = new RandomAccessInputStream(dataFile, "r")) { | |
224 | + instance.seek(136848); | |
225 | + byte[] buf = new byte[9]; | |
226 | + int len = instance.read(buf, 0, buf.length); | |
227 | + assertEquals(8, len); | |
228 | + assertEquals(5, buf[len - 2]); | |
229 | + assertEquals(0, buf[len - 1]); | |
230 | + pos = instance.position(); | |
231 | + } | |
230 | 232 | assertEquals(136856, pos); |
231 | 233 | } |
232 | 234 | } |