54 * read, an {@code EOFException} (which is a kind of
55 * {@code IOException}) is thrown. If any byte cannot be read for
56 * any reason other than end-of-file, an {@code IOException} other
57 * than {@code EOFException} is thrown. In particular, an
58 * {@code IOException} may be thrown if the stream has been closed.
59 *
60 * @since 1.0
61 */
62
63 public class RandomAccessFile implements DataOutput, DataInput, Closeable {
64
65 private static final int O_RDONLY = 1;
66 private static final int O_RDWR = 2;
67 private static final int O_SYNC = 4;
68 private static final int O_DSYNC = 8;
69 private static final int O_TEMPORARY = 16;
70
71 private final FileDescriptor fd;
72
73 private final boolean rw;
74
75 /**
76 * The path of the referenced file
77 * (null if the stream is created with a file descriptor)
78 */
79 private final String path;
80
81 private final Object closeLock = new Object();
82
83 /**
84 * A local buffer that allows reading and writing of
85 * longer primitive parameters (e.g. long) to be performed
86 * using bulk operations rather than on a per-byte basis.
87 */
88 private final byte[] buffer = new byte[Long.BYTES];
89
90 private volatile FileChannel channel;
91 private volatile boolean closed;
92
93 /**
212 * or the mode is {@code "rw"} and the security manager's
213 * {@code checkWrite} method denies write access to the file
214 * @see java.lang.SecurityManager#checkRead(java.lang.String)
215 * @see java.lang.SecurityManager#checkWrite(java.lang.String)
216 * @see java.nio.channels.FileChannel#force(boolean)
217 */
218 @SuppressWarnings("this-escape")
219 public RandomAccessFile(File file, String mode)
220 throws FileNotFoundException
221 {
222 this(file, mode, false);
223 }
224
225 private RandomAccessFile(File file, String mode, boolean openAndDelete)
226 throws FileNotFoundException
227 {
228 String name = (file != null ? file.getPath() : null);
229 int imode = -1;
230
231 boolean rw = false;
232 if (mode.equals("r"))
233 imode = O_RDONLY;
234 else if (mode.startsWith("rw")) {
235 imode = O_RDWR;
236 rw = true;
237 if (mode.length() > 2) {
238 if (mode.equals("rws"))
239 imode |= O_SYNC;
240 else if (mode.equals("rwd"))
241 imode |= O_DSYNC;
242 else
243 imode = -1;
244 }
245 }
246 this.rw = rw;
247
248 if (openAndDelete)
249 imode |= O_TEMPORARY;
250 if (imode < 0)
251 throw new IllegalArgumentException("Illegal mode \"" + mode
252 + "\" must be one of "
253 + "\"r\", \"rw\", \"rws\","
254 + " or \"rwd\"");
255 @SuppressWarnings("removal")
256 SecurityManager security = System.getSecurityManager();
257 if (security != null) {
258 security.checkRead(name);
259 if (rw) {
260 security.checkWrite(name);
261 }
262 }
263 if (name == null) {
264 throw new NullPointerException();
265 }
266 if (file.isInvalid()) {
291 *
292 * <p> The {@link java.nio.channels.FileChannel#position()
293 * position} of the returned channel will always be equal to
294 * this object's file-pointer offset as returned by the {@link
295 * #getFilePointer getFilePointer} method. Changing this object's
296 * file-pointer offset, whether explicitly or by reading or writing bytes,
297 * will change the position of the channel, and vice versa. Changing the
298 * file's length via this object will change the length seen via the file
299 * channel, and vice versa.
300 *
301 * @return the file channel associated with this file
302 *
303 * @since 1.4
304 */
305 public final FileChannel getChannel() {
306 FileChannel fc = this.channel;
307 if (fc == null) {
308 synchronized (this) {
309 fc = this.channel;
310 if (fc == null) {
311 this.channel = fc = FileChannelImpl.open(fd, path, true,
312 rw, false, this);
313 if (closed) {
314 try {
315 fc.close();
316 } catch (IOException ioe) {
317 throw new InternalError(ioe); // should not happen
318 }
319 }
320 }
321 }
322 }
323 return fc;
324 }
325
326 /**
327 * Opens a file and returns the file descriptor. The file is
328 * opened in read-write mode if the O_RDWR bit in {@code mode}
329 * is true, else the file is opened as read-only.
330 * If the {@code name} refers to a directory, an IOException
331 * is thrown.
332 *
333 * @param name the name of the file
334 * @param mode the mode flags, a combination of the O_ constants
335 * defined above
336 */
337 private native void open0(String name, int mode)
338 throws FileNotFoundException;
339
340 // wrap native call to allow instrumentation
341 /**
342 * Opens a file and returns the file descriptor. The file is
343 * opened in read-write mode if the O_RDWR bit in {@code mode}
344 * is true, else the file is opened as read-only.
345 * If the {@code name} refers to a directory, an IOException
346 * is thrown.
347 *
348 * @param name the name of the file
349 * @param mode the mode flags, a combination of the O_ constants
350 * defined above
351 */
352 private void open(String name, int mode) throws FileNotFoundException {
353 long comp = Blocker.begin();
354 try {
355 open0(name, mode);
356 } finally {
357 Blocker.end(comp);
358 }
359 }
360
361 // 'Read' primitives
362
363 /**
364 * Reads a byte of data from this file. The byte is returned as an
365 * integer in the range 0 to 255 ({@code 0x00-0x0ff}). This
366 * method blocks if no input is yet available.
367 * <p>
368 * Although {@code RandomAccessFile} is not a subclass of
369 * {@code InputStream}, this method behaves in exactly the same
370 * way as the {@link InputStream#read()} method of
371 * {@code InputStream}.
372 *
373 * @return the next byte of data, or {@code -1} if the end of the
374 * file has been reached.
375 * @throws IOException if an I/O error occurs. Not thrown if
376 * end-of-file has been reached.
377 */
378 public int read() throws IOException {
379 long comp = Blocker.begin();
380 try {
381 return read0();
382 } finally {
383 Blocker.end(comp);
384 }
385 }
386
387 private native int read0() throws IOException;
388
389 /**
390 * Reads a sub array as a sequence of bytes.
391 * @param b the buffer into which the data is read.
392 * @param off the start offset of the data.
393 * @param len the number of bytes to read.
394 * @throws IOException If an I/O error has occurred.
395 */
396 private int readBytes(byte[] b, int off, int len) throws IOException {
397 long comp = Blocker.begin();
398 try {
399 return readBytes0(b, off, len);
400 } finally {
401 Blocker.end(comp);
402 }
403 }
404
405 private native int readBytes0(byte[] b, int off, int len) throws IOException;
406
407 /**
408 * Reads up to {@code len} bytes of data from this file into an
409 * array of bytes. This method blocks until at least one byte of input
410 * is available.
411 * <p>
412 * Although {@code RandomAccessFile} is not a subclass of
413 * {@code InputStream}, this method behaves in exactly the
414 * same way as the {@link InputStream#read(byte[], int, int)} method of
415 * {@code InputStream}.
416 *
417 * @param b the buffer into which the data is read.
418 * @param off the start offset in array {@code b}
419 * at which the data is written.
420 * @param len the maximum number of bytes read.
421 * @return the total number of bytes read into the buffer, or
422 * {@code -1} if there is no more data because the end of
530 newpos = pos + n;
531 if (newpos > len) {
532 newpos = len;
533 }
534 seek(newpos);
535
536 /* return the actual number of bytes skipped */
537 return (int) (newpos - pos);
538 }
539
540 // 'Write' primitives
541
542 /**
543 * Writes the specified byte to this file. The write starts at
544 * the current file pointer.
545 *
546 * @param b the {@code byte} to be written.
547 * @throws IOException if an I/O error occurs.
548 */
549 public void write(int b) throws IOException {
550 long comp = Blocker.begin();
551 try {
552 write0(b);
553 } finally {
554 Blocker.end(comp);
555 }
556 }
557
558 private native void write0(int b) throws IOException;
559
560 /**
561 * Writes a sub array as a sequence of bytes.
562 *
563 * @param b the data to be written
564 * @param off the start offset in the data
565 * @param len the number of bytes that are written
566 * @throws IOException If an I/O error has occurred.
567 */
568 private void writeBytes(byte[] b, int off, int len) throws IOException {
569 long comp = Blocker.begin();
570 try {
571 writeBytes0(b, off, len);
572 } finally {
573 Blocker.end(comp);
574 }
575 }
576
577 private native void writeBytes0(byte[] b, int off, int len) throws IOException;
578
579 /**
580 * Writes {@code b.length} bytes from the specified byte array
581 * to this file, starting at the current file pointer.
582 *
583 * @param b the data.
584 * @throws IOException if an I/O error occurs.
585 */
586 public void write(byte[] b) throws IOException {
587 writeBytes(b, 0, b.length);
588 }
589
590 /**
591 * Writes {@code len} bytes from the specified byte array
592 * starting at offset {@code off} to this file.
593 *
613 public native long getFilePointer() throws IOException;
614
615 /**
616 * Sets the file-pointer offset, measured from the beginning of this
617 * file, at which the next read or write occurs. The offset may be
618 * set beyond the end of the file. Setting the offset beyond the end
619 * of the file does not change the file length. The file length will
620 * change only by writing after the offset has been set beyond the end
621 * of the file.
622 *
623 * @param pos the offset position, measured in bytes from the
624 * beginning of the file, at which to set the file
625 * pointer.
626 * @throws IOException if {@code pos} is less than
627 * {@code 0} or if an I/O error occurs.
628 */
629 public void seek(long pos) throws IOException {
630 if (pos < 0) {
631 throw new IOException("Negative seek offset");
632 }
633 long comp = Blocker.begin();
634 try {
635 seek0(pos);
636 } finally {
637 Blocker.end(comp);
638 }
639 }
640
641 private native void seek0(long pos) throws IOException;
642
643 /**
644 * Returns the length of this file.
645 *
646 * @return the length of this file, measured in bytes.
647 * @throws IOException if an I/O error occurs.
648 */
649 public long length() throws IOException {
650 long comp = Blocker.begin();
651 try {
652 return length0();
653 } finally {
654 Blocker.end(comp);
655 }
656 }
657
658 private native long length0() throws IOException;
659
660 /**
661 * Sets the length of this file.
662 *
663 * <p> If the present length of the file as returned by the
664 * {@linkplain #length length} method is greater than the desired length
665 * of the file specified by the {@code newLength} argument, then the file
666 * will be truncated.
667 *
668 * <p> If the present length of the file is smaller than the desired length,
669 * then the file will be extended. The contents of the extended portion of
670 * the file are not defined.
671 *
672 * <p> If the present length of the file is equal to the desired length,
673 * then the file and its length will be unchanged.
674 *
675 * <p> In all cases, after this method returns, the file offset as returned
676 * by the {@linkplain #getFilePointer getFilePointer} method will equal the
677 * minimum of the desired length and the file offset before this method was
678 * called, even if the length is unchanged. In other words, this method
679 * constrains the file offset to the closed interval {@code [0,newLength]}.
680 *
681 * @param newLength The desired length of the file
682 * @throws IOException If the argument is negative or
683 * if some other I/O error occurs
684 * @since 1.2
685 */
686 public void setLength(long newLength) throws IOException {
687 long comp = Blocker.begin();
688 try {
689 setLength0(newLength);
690 } finally {
691 Blocker.end(comp);
692 }
693 }
694
695 private native void setLength0(long newLength) throws IOException;
696
697 /**
698 * Closes this random access file stream and releases any system
699 * resources associated with the stream. A closed random access
700 * file cannot perform input or output operations and cannot be
701 * reopened.
702 *
703 * <p> If this file has an associated channel then the channel is closed
704 * as well.
705 *
706 * @apiNote
707 * If this stream has an associated channel then this method will close the
708 * channel, which in turn will close this stream. Subclasses that override
709 * this method should be prepared to handle possible reentrant invocation.
710 *
711 * @throws IOException if an I/O error occurs.
712 */
|
54 * read, an {@code EOFException} (which is a kind of
55 * {@code IOException}) is thrown. If any byte cannot be read for
56 * any reason other than end-of-file, an {@code IOException} other
57 * than {@code EOFException} is thrown. In particular, an
58 * {@code IOException} may be thrown if the stream has been closed.
59 *
60 * @since 1.0
61 */
62
63 public class RandomAccessFile implements DataOutput, DataInput, Closeable {
64
65 private static final int O_RDONLY = 1;
66 private static final int O_RDWR = 2;
67 private static final int O_SYNC = 4;
68 private static final int O_DSYNC = 8;
69 private static final int O_TEMPORARY = 16;
70
71 private final FileDescriptor fd;
72
73 private final boolean rw;
74 private final boolean sync; // O_SYNC or O_DSYNC
75
76 /**
77 * The path of the referenced file
78 * (null if the stream is created with a file descriptor)
79 */
80 private final String path;
81
82 private final Object closeLock = new Object();
83
84 /**
85 * A local buffer that allows reading and writing of
86 * longer primitive parameters (e.g. long) to be performed
87 * using bulk operations rather than on a per-byte basis.
88 */
89 private final byte[] buffer = new byte[Long.BYTES];
90
91 private volatile FileChannel channel;
92 private volatile boolean closed;
93
94 /**
213 * or the mode is {@code "rw"} and the security manager's
214 * {@code checkWrite} method denies write access to the file
215 * @see java.lang.SecurityManager#checkRead(java.lang.String)
216 * @see java.lang.SecurityManager#checkWrite(java.lang.String)
217 * @see java.nio.channels.FileChannel#force(boolean)
218 */
219 @SuppressWarnings("this-escape")
220 public RandomAccessFile(File file, String mode)
221 throws FileNotFoundException
222 {
223 this(file, mode, false);
224 }
225
226 private RandomAccessFile(File file, String mode, boolean openAndDelete)
227 throws FileNotFoundException
228 {
229 String name = (file != null ? file.getPath() : null);
230 int imode = -1;
231
232 boolean rw = false;
233 boolean sync = false;
234 if (mode.equals("r"))
235 imode = O_RDONLY;
236 else if (mode.startsWith("rw")) {
237 imode = O_RDWR;
238 rw = true;
239 if (mode.length() > 2) {
240 if (mode.equals("rws")) {
241 imode |= O_SYNC;
242 sync = true;
243 } else if (mode.equals("rwd")) {
244 imode |= O_DSYNC;
245 sync = true;
246 } else
247 imode = -1;
248 }
249 }
250 this.rw = rw;
251 this.sync = sync;
252
253 if (openAndDelete)
254 imode |= O_TEMPORARY;
255 if (imode < 0)
256 throw new IllegalArgumentException("Illegal mode \"" + mode
257 + "\" must be one of "
258 + "\"r\", \"rw\", \"rws\","
259 + " or \"rwd\"");
260 @SuppressWarnings("removal")
261 SecurityManager security = System.getSecurityManager();
262 if (security != null) {
263 security.checkRead(name);
264 if (rw) {
265 security.checkWrite(name);
266 }
267 }
268 if (name == null) {
269 throw new NullPointerException();
270 }
271 if (file.isInvalid()) {
296 *
297 * <p> The {@link java.nio.channels.FileChannel#position()
298 * position} of the returned channel will always be equal to
299 * this object's file-pointer offset as returned by the {@link
300 * #getFilePointer getFilePointer} method. Changing this object's
301 * file-pointer offset, whether explicitly or by reading or writing bytes,
302 * will change the position of the channel, and vice versa. Changing the
303 * file's length via this object will change the length seen via the file
304 * channel, and vice versa.
305 *
306 * @return the file channel associated with this file
307 *
308 * @since 1.4
309 */
310 public final FileChannel getChannel() {
311 FileChannel fc = this.channel;
312 if (fc == null) {
313 synchronized (this) {
314 fc = this.channel;
315 if (fc == null) {
316 fc = FileChannelImpl.open(fd, path, true, rw, sync, false, this);
317 this.channel = fc;
318 if (closed) {
319 try {
320 fc.close();
321 } catch (IOException ioe) {
322 throw new InternalError(ioe); // should not happen
323 }
324 }
325 }
326 }
327 }
328 return fc;
329 }
330
331 /**
332 * Opens a file and returns the file descriptor. The file is
333 * opened in read-write mode if the O_RDWR bit in {@code mode}
334 * is true, else the file is opened as read-only.
335 * If the {@code name} refers to a directory, an IOException
336 * is thrown.
337 *
338 * @param name the name of the file
339 * @param mode the mode flags, a combination of the O_ constants
340 * defined above
341 */
342 private native void open0(String name, int mode)
343 throws FileNotFoundException;
344
345 // wrap native call to allow instrumentation
346 /**
347 * Opens a file and returns the file descriptor. The file is
348 * opened in read-write mode if the O_RDWR bit in {@code mode}
349 * is true, else the file is opened as read-only.
350 * If the {@code name} refers to a directory, an IOException
351 * is thrown.
352 *
353 * @param name the name of the file
354 * @param mode the mode flags, a combination of the O_ constants
355 * defined above
356 */
357 private void open(String name, int mode) throws FileNotFoundException {
358 open0(name, mode);
359 }
360
361 // 'Read' primitives
362
363 /**
364 * Reads a byte of data from this file. The byte is returned as an
365 * integer in the range 0 to 255 ({@code 0x00-0x0ff}). This
366 * method blocks if no input is yet available.
367 * <p>
368 * Although {@code RandomAccessFile} is not a subclass of
369 * {@code InputStream}, this method behaves in exactly the same
370 * way as the {@link InputStream#read()} method of
371 * {@code InputStream}.
372 *
373 * @return the next byte of data, or {@code -1} if the end of the
374 * file has been reached.
375 * @throws IOException if an I/O error occurs. Not thrown if
376 * end-of-file has been reached.
377 */
378 public int read() throws IOException {
379 return read0();
380 }
381
382 private native int read0() throws IOException;
383
384 /**
385 * Reads a sub array as a sequence of bytes.
386 * @param b the buffer into which the data is read.
387 * @param off the start offset of the data.
388 * @param len the number of bytes to read.
389 * @throws IOException If an I/O error has occurred.
390 */
391 private int readBytes(byte[] b, int off, int len) throws IOException {
392 return readBytes0(b, off, len);
393 }
394
395 private native int readBytes0(byte[] b, int off, int len) throws IOException;
396
397 /**
398 * Reads up to {@code len} bytes of data from this file into an
399 * array of bytes. This method blocks until at least one byte of input
400 * is available.
401 * <p>
402 * Although {@code RandomAccessFile} is not a subclass of
403 * {@code InputStream}, this method behaves in exactly the
404 * same way as the {@link InputStream#read(byte[], int, int)} method of
405 * {@code InputStream}.
406 *
407 * @param b the buffer into which the data is read.
408 * @param off the start offset in array {@code b}
409 * at which the data is written.
410 * @param len the maximum number of bytes read.
411 * @return the total number of bytes read into the buffer, or
412 * {@code -1} if there is no more data because the end of
520 newpos = pos + n;
521 if (newpos > len) {
522 newpos = len;
523 }
524 seek(newpos);
525
526 /* return the actual number of bytes skipped */
527 return (int) (newpos - pos);
528 }
529
530 // 'Write' primitives
531
532 /**
533 * Writes the specified byte to this file. The write starts at
534 * the current file pointer.
535 *
536 * @param b the {@code byte} to be written.
537 * @throws IOException if an I/O error occurs.
538 */
539 public void write(int b) throws IOException {
540 boolean attempted = Blocker.begin(sync);
541 try {
542 write0(b);
543 } finally {
544 Blocker.end(attempted);
545 }
546 }
547
548 private native void write0(int b) throws IOException;
549
550 /**
551 * Writes a sub array as a sequence of bytes.
552 *
553 * @param b the data to be written
554 * @param off the start offset in the data
555 * @param len the number of bytes that are written
556 * @throws IOException If an I/O error has occurred.
557 */
558 private void writeBytes(byte[] b, int off, int len) throws IOException {
559 boolean attempted = Blocker.begin(sync);
560 try {
561 writeBytes0(b, off, len);
562 } finally {
563 Blocker.end(attempted);
564 }
565 }
566
567 private native void writeBytes0(byte[] b, int off, int len) throws IOException;
568
569 /**
570 * Writes {@code b.length} bytes from the specified byte array
571 * to this file, starting at the current file pointer.
572 *
573 * @param b the data.
574 * @throws IOException if an I/O error occurs.
575 */
576 public void write(byte[] b) throws IOException {
577 writeBytes(b, 0, b.length);
578 }
579
580 /**
581 * Writes {@code len} bytes from the specified byte array
582 * starting at offset {@code off} to this file.
583 *
603 public native long getFilePointer() throws IOException;
604
605 /**
606 * Sets the file-pointer offset, measured from the beginning of this
607 * file, at which the next read or write occurs. The offset may be
608 * set beyond the end of the file. Setting the offset beyond the end
609 * of the file does not change the file length. The file length will
610 * change only by writing after the offset has been set beyond the end
611 * of the file.
612 *
613 * @param pos the offset position, measured in bytes from the
614 * beginning of the file, at which to set the file
615 * pointer.
616 * @throws IOException if {@code pos} is less than
617 * {@code 0} or if an I/O error occurs.
618 */
619 public void seek(long pos) throws IOException {
620 if (pos < 0) {
621 throw new IOException("Negative seek offset");
622 }
623 seek0(pos);
624 }
625
626 private native void seek0(long pos) throws IOException;
627
628 /**
629 * Returns the length of this file.
630 *
631 * @return the length of this file, measured in bytes.
632 * @throws IOException if an I/O error occurs.
633 */
634 public long length() throws IOException {
635 return length0();
636 }
637
638 private native long length0() throws IOException;
639
640 /**
641 * Sets the length of this file.
642 *
643 * <p> If the present length of the file as returned by the
644 * {@linkplain #length length} method is greater than the desired length
645 * of the file specified by the {@code newLength} argument, then the file
646 * will be truncated.
647 *
648 * <p> If the present length of the file is smaller than the desired length,
649 * then the file will be extended. The contents of the extended portion of
650 * the file are not defined.
651 *
652 * <p> If the present length of the file is equal to the desired length,
653 * then the file and its length will be unchanged.
654 *
655 * <p> In all cases, after this method returns, the file offset as returned
656 * by the {@linkplain #getFilePointer getFilePointer} method will equal the
657 * minimum of the desired length and the file offset before this method was
658 * called, even if the length is unchanged. In other words, this method
659 * constrains the file offset to the closed interval {@code [0,newLength]}.
660 *
661 * @param newLength The desired length of the file
662 * @throws IOException If the argument is negative or
663 * if some other I/O error occurs
664 * @since 1.2
665 */
666 public void setLength(long newLength) throws IOException {
667 setLength0(newLength);
668 }
669
670 private native void setLength0(long newLength) throws IOException;
671
672 /**
673 * Closes this random access file stream and releases any system
674 * resources associated with the stream. A closed random access
675 * file cannot perform input or output operations and cannot be
676 * reopened.
677 *
678 * <p> If this file has an associated channel then the channel is closed
679 * as well.
680 *
681 * @apiNote
682 * If this stream has an associated channel then this method will close the
683 * channel, which in turn will close this stream. Subclasses that override
684 * this method should be prepared to handle possible reentrant invocation.
685 *
686 * @throws IOException if an I/O error occurs.
687 */
|