@@ -60,9 +60,12 @@ public class FileHandle extends AbstractDataHandle<FileLocation> {
6060
6161 // -- FileHandle methods --
6262
63- /** Gets the random access file object backing this FileHandle. */
63+ /**
64+ * Gets the random access file object backing this FileHandle. If the
65+ * underlying file does not exist yet, it will be created.
66+ */
6467 public RandomAccessFile getRandomAccessFile () throws IOException {
65- return raf ();
68+ return writer ();
6669 }
6770
6871 public String getMode () {
@@ -101,199 +104,199 @@ public Date lastModified() {
101104
102105 @ Override
103106 public long offset () throws IOException {
104- return raf () .getFilePointer ();
107+ return exists () ? reader () .getFilePointer () : 0 ;
105108 }
106109
107110 @ Override
108111 public long length () throws IOException {
109- return exists () ? raf ().length () : -1 ;
112+ return exists () ? reader ().length () : -1 ;
110113 }
111114
112115 @ Override
113116 public void setLength (final long length ) throws IOException {
114- raf ().setLength (length );
117+ writer ().setLength (length );
115118 }
116119
117120 @ Override
118121 public int read () throws IOException {
119- return raf ().read ();
122+ return reader ().read ();
120123 }
121124
122125 @ Override
123126 public int read (final byte [] b ) throws IOException {
124- return raf ().read (b );
127+ return reader ().read (b );
125128 }
126129
127130 @ Override
128131 public int read (final byte [] b , final int off , final int len )
129132 throws IOException
130133 {
131- return raf ().read (b , off , len );
134+ return reader ().read (b , off , len );
132135 }
133136
134137 @ Override
135138 public void seek (final long pos ) throws IOException {
136- raf ().seek (pos );
139+ reader ().seek (pos );
137140 }
138141
139142 // -- DataInput methods --
140143
141144 @ Override
142145 public boolean readBoolean () throws IOException {
143- return raf ().readBoolean ();
146+ return reader ().readBoolean ();
144147 }
145148
146149 @ Override
147150 public byte readByte () throws IOException {
148- return raf ().readByte ();
151+ return reader ().readByte ();
149152 }
150153
151154 @ Override
152155 public char readChar () throws IOException {
153- return raf ().readChar ();
156+ return reader ().readChar ();
154157 }
155158
156159 @ Override
157160 public double readDouble () throws IOException {
158- return raf ().readDouble ();
161+ return reader ().readDouble ();
159162 }
160163
161164 @ Override
162165 public float readFloat () throws IOException {
163- return raf ().readFloat ();
166+ return reader ().readFloat ();
164167 }
165168
166169 @ Override
167170 public void readFully (final byte [] b ) throws IOException {
168- raf ().readFully (b );
171+ reader ().readFully (b );
169172 }
170173
171174 @ Override
172175 public void readFully (final byte [] b , final int off , final int len )
173176 throws IOException
174177 {
175- raf ().readFully (b , off , len );
178+ reader ().readFully (b , off , len );
176179 }
177180
178181 @ Override
179182 public int readInt () throws IOException {
180- return raf ().readInt ();
183+ return reader ().readInt ();
181184 }
182185
183186 @ Override
184187 public String readLine () throws IOException {
185- return raf ().readLine ();
188+ return reader ().readLine ();
186189 }
187190
188191 @ Override
189192 public long readLong () throws IOException {
190- return raf ().readLong ();
193+ return reader ().readLong ();
191194 }
192195
193196 @ Override
194197 public short readShort () throws IOException {
195- return raf ().readShort ();
198+ return reader ().readShort ();
196199 }
197200
198201 @ Override
199202 public int readUnsignedByte () throws IOException {
200- return raf ().readUnsignedByte ();
203+ return reader ().readUnsignedByte ();
201204 }
202205
203206 @ Override
204207 public int readUnsignedShort () throws IOException {
205- return raf ().readUnsignedShort ();
208+ return reader ().readUnsignedShort ();
206209 }
207210
208211 @ Override
209212 public String readUTF () throws IOException {
210- return raf ().readUTF ();
213+ return reader ().readUTF ();
211214 }
212215
213216 @ Override
214217 public int skipBytes (final int n ) throws IOException {
215- return raf ().skipBytes (n );
218+ return reader ().skipBytes (n );
216219 }
217220
218221 // -- DataOutput methods --
219222
220223 @ Override
221224 public void write (final byte [] b ) throws IOException {
222- raf ().write (b );
225+ writer ().write (b );
223226 }
224227
225228 @ Override
226229 public void write (final byte [] b , final int off , final int len )
227230 throws IOException
228231 {
229- raf ().write (b , off , len );
232+ writer ().write (b , off , len );
230233 }
231234
232235 @ Override
233236 public void write (final int b ) throws IOException {
234- raf ().write (b );
237+ writer ().write (b );
235238 }
236239
237240 @ Override
238241 public void writeBoolean (final boolean v ) throws IOException {
239- raf ().writeBoolean (v );
242+ writer ().writeBoolean (v );
240243 }
241244
242245 @ Override
243246 public void writeByte (final int v ) throws IOException {
244- raf ().writeByte (v );
247+ writer ().writeByte (v );
245248 }
246249
247250 @ Override
248251 public void writeBytes (final String s ) throws IOException {
249- raf ().writeBytes (s );
252+ writer ().writeBytes (s );
250253 }
251254
252255 @ Override
253256 public void writeChar (final int v ) throws IOException {
254- raf ().writeChar (v );
257+ writer ().writeChar (v );
255258 }
256259
257260 @ Override
258261 public void writeChars (final String s ) throws IOException {
259- raf ().writeChars (s );
262+ writer ().writeChars (s );
260263 }
261264
262265 @ Override
263266 public void writeDouble (final double v ) throws IOException {
264- raf ().writeDouble (v );
267+ writer ().writeDouble (v );
265268 }
266269
267270 @ Override
268271 public void writeFloat (final float v ) throws IOException {
269- raf ().writeFloat (v );
272+ writer ().writeFloat (v );
270273 }
271274
272275 @ Override
273276 public void writeInt (final int v ) throws IOException {
274- raf ().writeInt (v );
277+ writer ().writeInt (v );
275278 }
276279
277280 @ Override
278281 public void writeLong (final long v ) throws IOException {
279- raf ().writeLong (v );
282+ writer ().writeLong (v );
280283 }
281284
282285 @ Override
283286 public void writeShort (final int v ) throws IOException {
284- raf ().writeShort (v );
287+ writer ().writeShort (v );
285288 }
286289
287290 @ Override
288291 public void writeUTF (final String str ) throws IOException {
289- raf ().writeUTF (str );
292+ writer ().writeUTF (str );
290293 }
291294
292295 // -- Closeable methods --
293296
294297 @ Override
295298 public synchronized void close () throws IOException {
296- if (raf != null ) raf () .close ();
299+ if (raf != null ) raf .close ();
297300 closed = true ;
298301 }
299302
@@ -306,12 +309,47 @@ public Class<FileLocation> getType() {
306309
307310 // -- Helper methods --
308311
309- private RandomAccessFile raf () throws IOException {
310- if (raf == null ) initRAF ();
312+ /**
313+ * Access method for the internal {@link RandomAccessFile}, that succeeds
314+ * independently of the underlying file existing on disk. This allows us to
315+ * create a new file for writing.
316+ *
317+ * @return the internal {@link RandomAccessFile} creating a new file on disk
318+ * if needed.
319+ * @throws IOException if the {@link RandomAccessFile} could not be created.
320+ */
321+ private RandomAccessFile writer () throws IOException {
322+ if (raf == null ) initRAF (true );
311323 return raf ;
312324 }
313325
314- private synchronized void initRAF () throws IOException {
326+ /**
327+ * Access method for the internal {@link RandomAccessFile}, that only succeeds
328+ * if the underlying file exists on disk. This prevents accidental creation of
329+ * an empty file when calling read operations on a non-existent file.
330+ *
331+ * @return the internal {@link RandomAccessFile}.
332+ * @throws IOException if the {@link RandomAccessFile} could not be created,
333+ * or the backing file does not exists.
334+ */
335+ private RandomAccessFile reader () throws IOException {
336+ if (raf == null ) initRAF (false );
337+ return raf ;
338+ }
339+
340+ /**
341+ * Initializes the {@link RandomAccessFile}.
342+ *
343+ * @param create whether to create the {@link RandomAccessFile} if the
344+ * underlying file does not exist yet.
345+ * @throws IOException if the {@link RandomAccessFile} could not be created,
346+ * or the backing file does not exist and the {@code create}
347+ * parameter was set to {@code false}.
348+ */
349+ private synchronized void initRAF (final boolean create ) throws IOException {
350+ if (!create && !exists ()) {
351+ throw new IOException ("Trying to read from non-existent file!" );
352+ }
315353 if (closed ) throw new IOException ("Handle already closed" );
316354 if (raf != null ) return ;
317355 raf = new RandomAccessFile (get ().getFile (), getMode ());
0 commit comments