1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.archive.io;
24
25
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.RandomAccessFile;
29
30
31 /***
32 * Wraps a RandomAccessFile with an InputStream interface.
33 *
34 * @author gojomo
35 */
36 public class RandomAccessInputStream extends SeekInputStream {
37
38 /***
39 * Reference to the random access file this stream is reading from.
40 */
41 private RandomAccessFile raf = null;
42
43 /***
44 * When mark is called, save here the current position so we can go back
45 * on reset.
46 */
47 private long markpos = -1;
48
49 /***
50 * True if we are to close the underlying random access file when this
51 * stream is closed.
52 */
53 private boolean sympathyClose;
54
55 /***
56 * Constructor.
57 *
58 * If using this constructor, caller created the RAF and therefore
59 * its assumed wants to control close of the RAF. The RAF.close
60 * is not called if this constructor is used on close of this stream.
61 *
62 * @param raf RandomAccessFile to wrap.
63 * @throws IOException
64 */
65 public RandomAccessInputStream(RandomAccessFile raf)
66 throws IOException {
67 this(raf, false, 0);
68 }
69
70 /***
71 * Constructor.
72 *
73 * @param file File to get RAFIS on. Creates an RAF from passed file.
74 * Closes the created RAF when this stream is closed.
75 * @throws IOException
76 */
77 public RandomAccessInputStream(final File file)
78 throws IOException {
79 this(new RandomAccessFile(file, "r"), true, 0);
80 }
81
82 /***
83 * Constructor.
84 *
85 * @param file File to get RAFIS on. Creates an RAF from passed file.
86 * Closes the created RAF when this stream is closed.
87 * @param offset
88 * @throws IOException
89 */
90 public RandomAccessInputStream(final File file, final long offset)
91 throws IOException {
92 this(new RandomAccessFile(file, "r"), true, offset);
93 }
94
95 /***
96 * @param raf RandomAccessFile to wrap.
97 * @param sympathyClose Set to true if we are to close the RAF
98 * file when this stream is closed.
99 * @param offset
100 * @throws IOException
101 */
102 public RandomAccessInputStream(final RandomAccessFile raf,
103 final boolean sympathyClose, final long offset)
104 throws IOException {
105 super();
106 this.sympathyClose = sympathyClose;
107 this.raf = raf;
108 if (offset > 0) {
109 this.raf.seek(offset);
110 }
111 }
112
113
114
115
116 public int read() throws IOException {
117 return this.raf.read();
118 }
119
120
121
122
123 public int read(byte[] b, int off, int len) throws IOException {
124 return this.raf.read(b, off, len);
125 }
126
127
128
129
130 public int read(byte[] b) throws IOException {
131 return this.raf.read(b);
132 }
133
134
135
136
137 public long skip(long n) throws IOException {
138 this.raf.seek(this.raf.getFilePointer() + n);
139 return n;
140 }
141
142 public long position() throws IOException {
143 return this.raf.getFilePointer();
144 }
145
146 public void position(long position) throws IOException {
147 this.raf.seek(position);
148 }
149
150 public int available() throws IOException {
151 long amount = this.raf.length() - this.position();
152 return (amount >= Integer.MAX_VALUE)? Integer.MAX_VALUE: (int)amount;
153 }
154
155 public boolean markSupported() {
156 return true;
157 }
158
159 public synchronized void mark(int readlimit) {
160 try {
161 this.markpos = position();
162 } catch (IOException e) {
163
164 this.markpos = -1;
165 }
166 }
167
168 public synchronized void reset() throws IOException {
169 if (this.markpos == -1) {
170 throw new IOException("Mark has not been set.");
171 }
172 position(this.markpos);
173 }
174
175 public void close() throws IOException {
176 try {
177 super.close();
178 } finally {
179 if (this.sympathyClose) {
180 this.raf.close();
181 }
182 }
183 }
184 }