47 * {@code getFilePointer} method and set by the {@code seek} 48 * method. 49 * <p> 50 * It is generally true of all the reading routines in this class that 51 * if end-of-file is reached before the desired number of bytes has been 52 * read, an {@code EOFException} (which is a kind of 53 * {@code IOException}) is thrown. If any byte cannot be read for 54 * any reason other than end-of-file, an {@code IOException} other 55 * than {@code EOFException} is thrown. In particular, an 56 * {@code IOException} may be thrown if the stream has been closed. 57 * 58 * @author unascribed 59 * @since 1.0 60 */ 61 62 public class RandomAccessFile implements DataOutput, DataInput, Closeable { 63 64 private FileDescriptor fd; 65 private volatile FileChannel channel; 66 private boolean rw; 67 68 /** 69 * The path of the referenced file 70 * (null if the stream is created with a file descriptor) 71 */ 72 private final String path; 73 74 private final AtomicBoolean closed = new AtomicBoolean(false); 75 76 private static final int O_RDONLY = 1; 77 private static final int O_RDWR = 2; 78 private static final int O_SYNC = 4; 79 private static final int O_DSYNC = 8; 80 private static final int O_TEMPORARY = 16; 81 82 /** 83 * Creates a random access file stream to read from, and optionally 84 * to write to, a file with the specified name. A new 85 * {@link FileDescriptor} object is created to represent the 86 * connection to the file. 87 * 88 * <p> The {@code mode} argument specifies the access mode with which the 89 * file is to be opened. The permitted values and their meanings are as 90 * specified for the <a 91 * href="#mode">{@code RandomAccessFile(File,String)}</a> constructor. 92 * 93 * <p> 94 * If there is a security manager, its {@code checkRead} method 95 * is called with the {@code name} argument 96 * as its argument to see if read access to the file is allowed. 97 * If the mode allows writing, the security manager's 98 * {@code checkWrite} method 99 * is also called with the {@code name} argument 100 * as its argument to see if write access to the file is allowed. 199 * {@code checkWrite} method denies write access to the file 200 * @see java.lang.SecurityManager#checkRead(java.lang.String) 201 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 202 * @see java.nio.channels.FileChannel#force(boolean) 203 * @revised 1.4 204 * @spec JSR-51 205 */ 206 public RandomAccessFile(File file, String mode) 207 throws FileNotFoundException 208 { 209 this(file, mode, false); 210 } 211 212 private RandomAccessFile(File file, String mode, boolean openAndDelete) 213 throws FileNotFoundException 214 { 215 String name = (file != null ? file.getPath() : null); 216 int imode = -1; 217 if (mode.equals("r")) 218 imode = O_RDONLY; 219 else if (mode.startsWith("rw")) { 220 imode = O_RDWR; 221 rw = true; 222 if (mode.length() > 2) { 223 if (mode.equals("rws")) 224 imode |= O_SYNC; 225 else if (mode.equals("rwd")) 226 imode |= O_DSYNC; 227 else 228 imode = -1; 229 } 230 } 231 if (openAndDelete) 232 imode |= O_TEMPORARY; 233 if (imode < 0) 234 throw new IllegalArgumentException("Illegal mode \"" + mode 235 + "\" must be one of " 236 + "\"r\", \"rw\", \"rws\"," 237 + " or \"rwd\""); 238 SecurityManager security = System.getSecurityManager(); 239 if (security != null) { 240 security.checkRead(name); 241 if (rw) { 242 security.checkWrite(name); 243 } 244 } 245 if (name == null) { 246 throw new NullPointerException(); 247 } 248 if (file.isInvalid()) { 249 throw new FileNotFoundException("Invalid file path"); 250 } 251 fd = new FileDescriptor(); 252 fd.attach(this); 253 path = name; 254 open(name, imode); 255 } 256 257 /** 321 private native void open0(String name, int mode) 322 throws FileNotFoundException; 323 324 // wrap native call to allow instrumentation 325 /** 326 * Opens a file and returns the file descriptor. The file is 327 * opened in read-write mode if the O_RDWR bit in {@code mode} 328 * is true, else the file is opened as read-only. 329 * If the {@code name} refers to a directory, an IOException 330 * is thrown. 331 * 332 * @param name the name of the file 333 * @param mode the mode flags, a combination of the O_ constants 334 * defined above 335 */ 336 private void open(String name, int mode) 337 throws FileNotFoundException { 338 open0(name, mode); 339 } 340 341 // 'Read' primitives 342 343 /** 344 * Reads a byte of data from this file. The byte is returned as an 345 * integer in the range 0 to 255 ({@code 0x00-0x0ff}). This 346 * method blocks if no input is yet available. 347 * <p> 348 * Although {@code RandomAccessFile} is not a subclass of 349 * {@code InputStream}, this method behaves in exactly the same 350 * way as the {@link InputStream#read()} method of 351 * {@code InputStream}. 352 * 353 * @return the next byte of data, or {@code -1} if the end of the 354 * file has been reached. 355 * @exception IOException if an I/O error occurs. Not thrown if 356 * end-of-file has been reached. 357 */ 358 public int read() throws IOException { 359 return read0(); 360 } 361 362 private native int read0() throws IOException; 363 364 /** 365 * Reads a sub array as a sequence of bytes. 366 * @param b the buffer into which the data is read. 367 * @param off the start offset of the data. 368 * @param len the number of bytes to read. 369 * @exception IOException If an I/O error has occurred. 370 */ 371 private native int readBytes(byte b[], int off, int len) throws IOException; 372 373 /** 374 * Reads up to {@code len} bytes of data from this file into an 375 * array of bytes. This method blocks until at least one byte of input 376 * is available. 377 * <p> 378 * Although {@code RandomAccessFile} is not a subclass of 379 * {@code InputStream}, this method behaves in exactly the 380 * same way as the {@link InputStream#read(byte[], int, int)} method of 381 * {@code InputStream}. 382 * 383 * @param b the buffer into which the data is read. 384 * @param off the start offset in array {@code b} 385 * at which the data is written. 386 * @param len the maximum number of bytes read. 387 * @return the total number of bytes read into the buffer, or 388 * {@code -1} if there is no more data because the end of 389 * the file has been reached. 390 * @exception IOException If the first byte cannot be read for any reason 391 * other than end of file, or if the random access file has been closed, or if 392 * some other I/O error occurs. 393 * @exception NullPointerException If {@code b} is {@code null}. 394 * @exception IndexOutOfBoundsException If {@code off} is negative, 395 * {@code len} is negative, or {@code len} is greater than 396 * {@code b.length - off} 397 */ 398 public int read(byte b[], int off, int len) throws IOException { 399 return readBytes(b, off, len); 400 } 401 402 /** 403 * Reads up to {@code b.length} bytes of data from this file 404 * into an array of bytes. This method blocks until at least one byte 405 * of input is available. 406 * <p> 407 * Although {@code RandomAccessFile} is not a subclass of 408 * {@code InputStream}, this method behaves in exactly the 409 * same way as the {@link InputStream#read(byte[])} method of 410 * {@code InputStream}. 411 * 412 * @param b the buffer into which the data is read. 413 * @return the total number of bytes read into the buffer, or 414 * {@code -1} if there is no more data because the end of 415 * this file has been reached. 416 * @exception IOException If the first byte cannot be read for any reason 417 * other than end of file, or if the random access file has been closed, or if 418 * some other I/O error occurs. 419 * @exception NullPointerException If {@code b} is {@code null}. 420 */ 421 public int read(byte b[]) throws IOException { 422 return readBytes(b, 0, b.length); 423 } 424 425 /** 426 * Reads {@code b.length} bytes from this file into the byte 427 * array, starting at the current file pointer. This method reads 428 * repeatedly from the file until the requested number of bytes are 429 * read. This method blocks until the requested number of bytes are 430 * read, the end of the stream is detected, or an exception is thrown. 431 * 432 * @param b the buffer into which the data is read. 433 * @throws NullPointerException if {@code b} is {@code null}. 434 * @throws EOFException if this file reaches the end before reading 435 * all the bytes. 436 * @throws IOException if an I/O error occurs. 437 */ 438 public final void readFully(byte b[]) throws IOException { 439 readFully(b, 0, b.length); 440 } 441 512 * @param b the {@code byte} to be written. 513 * @exception IOException if an I/O error occurs. 514 */ 515 public void write(int b) throws IOException { 516 write0(b); 517 } 518 519 private native void write0(int b) throws IOException; 520 521 /** 522 * Writes a sub array as a sequence of bytes. 523 * @param b the data to be written 524 525 * @param off the start offset in the data 526 * @param len the number of bytes that are written 527 * @exception IOException If an I/O error has occurred. 528 */ 529 private native void writeBytes(byte b[], int off, int len) throws IOException; 530 531 /** 532 * Writes {@code b.length} bytes from the specified byte array 533 * to this file, starting at the current file pointer. 534 * 535 * @param b the data. 536 * @exception IOException if an I/O error occurs. 537 */ 538 public void write(byte b[]) throws IOException { 539 writeBytes(b, 0, b.length); 540 } 541 542 /** 543 * Writes {@code len} bytes from the specified byte array 544 * starting at offset {@code off} to this file. 545 * 546 * @param b the data. 547 * @param off the start offset in the data. 548 * @param len the number of bytes to write. 549 * @exception IOException if an I/O error occurs. 550 */ 551 public void write(byte b[], int off, int len) throws IOException { 552 writeBytes(b, off, len); 553 } 554 555 // 'Random access' stuff 556 557 /** 558 * Returns the current offset in this file. 559 * 560 * @return the offset from the beginning of the file, in bytes, 561 * at which the next read or write occurs. 562 * @exception IOException if an I/O error occurs. 563 */ 564 public native long getFilePointer() throws IOException; 565 566 /** 567 * Sets the file-pointer offset, measured from the beginning of this 568 * file, at which the next read or write occurs. The offset may be 569 * set beyond the end of the file. Setting the offset beyond the end 570 * of the file does not change the file length. The file length will 571 * change only by writing after the offset has been set beyond the end 572 * of the file. 573 * 574 * @param pos the offset position, measured in bytes from the 575 * beginning of the file, at which to set the file 576 * pointer. 577 * @exception IOException if {@code pos} is less than 578 * {@code 0} or if an I/O error occurs. 579 */ 580 public void seek(long pos) throws IOException { 581 if (pos < 0) { 582 throw new IOException("Negative seek offset"); 583 } else { 584 seek0(pos); 585 } 586 } 587 588 private native void seek0(long pos) throws IOException; 589 590 /** 591 * Returns the length of this file. 592 * 593 * @return the length of this file, measured in bytes. 594 * @exception IOException if an I/O error occurs. 595 */ 596 public native long length() throws IOException; 597 598 /** 599 * Sets the length of this file. 600 * 601 * <p> If the present length of the file as returned by the 602 * {@code length} method is greater than the {@code newLength} 603 * argument then the file will be truncated. In this case, if the file 604 * offset as returned by the {@code getFilePointer} method is greater 605 * than {@code newLength} then after this method returns the offset 606 * will be equal to {@code newLength}. 607 * 608 * <p> If the present length of the file as returned by the | 47 * {@code getFilePointer} method and set by the {@code seek} 48 * method. 49 * <p> 50 * It is generally true of all the reading routines in this class that 51 * if end-of-file is reached before the desired number of bytes has been 52 * read, an {@code EOFException} (which is a kind of 53 * {@code IOException}) is thrown. If any byte cannot be read for 54 * any reason other than end-of-file, an {@code IOException} other 55 * than {@code EOFException} is thrown. In particular, an 56 * {@code IOException} may be thrown if the stream has been closed. 57 * 58 * @author unascribed 59 * @since 1.0 60 */ 61 62 public class RandomAccessFile implements DataOutput, DataInput, Closeable { 63 64 private FileDescriptor fd; 65 private volatile FileChannel channel; 66 private boolean rw; 67 private boolean direct = false; 68 private int pageSize = -1; 69 70 /** 71 * The path of the referenced file 72 * (null if the stream is created with a file descriptor) 73 */ 74 private final String path; 75 76 private final AtomicBoolean closed = new AtomicBoolean(false); 77 78 private static final int O_RDONLY = 1; 79 private static final int O_RDWR = 2; 80 private static final int O_SYNC = 4; 81 private static final int O_DSYNC = 8; 82 private static final int O_TEMPORARY = 16; 83 private static final int O_DIRECT = 32; 84 85 /** 86 * Creates a random access file stream to read from, and optionally 87 * to write to, a file with the specified name. A new 88 * {@link FileDescriptor} object is created to represent the 89 * connection to the file. 90 * 91 * <p> The {@code mode} argument specifies the access mode with which the 92 * file is to be opened. The permitted values and their meanings are as 93 * specified for the <a 94 * href="#mode">{@code RandomAccessFile(File,String)}</a> constructor. 95 * 96 * <p> 97 * If there is a security manager, its {@code checkRead} method 98 * is called with the {@code name} argument 99 * as its argument to see if read access to the file is allowed. 100 * If the mode allows writing, the security manager's 101 * {@code checkWrite} method 102 * is also called with the {@code name} argument 103 * as its argument to see if write access to the file is allowed. 202 * {@code checkWrite} method denies write access to the file 203 * @see java.lang.SecurityManager#checkRead(java.lang.String) 204 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 205 * @see java.nio.channels.FileChannel#force(boolean) 206 * @revised 1.4 207 * @spec JSR-51 208 */ 209 public RandomAccessFile(File file, String mode) 210 throws FileNotFoundException 211 { 212 this(file, mode, false); 213 } 214 215 private RandomAccessFile(File file, String mode, boolean openAndDelete) 216 throws FileNotFoundException 217 { 218 String name = (file != null ? file.getPath() : null); 219 int imode = -1; 220 if (mode.equals("r")) 221 imode = O_RDONLY; 222 else if (mode.equals("ro")) { 223 imode = O_RDONLY | O_DIRECT; 224 direct = true; 225 getPageSize(); 226 } 227 else if (mode.startsWith("rw")) { 228 imode = O_RDWR; 229 rw = true; 230 if (mode.length() > 2) { 231 if (mode.equals("rws")) 232 imode |= O_SYNC; 233 else if (mode.equals("rwd")) 234 imode |= O_DSYNC; 235 else if (mode.equals("rwo")) { 236 imode |= O_DIRECT; 237 direct = true; 238 getPageSize(); 239 } 240 else 241 imode = -1; 242 } 243 } 244 if (openAndDelete) 245 imode |= O_TEMPORARY; 246 if (imode < 0) 247 throw new IllegalArgumentException("Illegal mode \"" + mode 248 + "\" must be one of " 249 + "\"r\", \"ro\", \"rw\", \"rws\", \"rwd\"" 250 + " or \"rwo\""); 251 SecurityManager security = System.getSecurityManager(); 252 if (security != null) { 253 security.checkRead(name); 254 if (rw) { 255 security.checkWrite(name); 256 } 257 } 258 if (name == null) { 259 throw new NullPointerException(); 260 } 261 if (file.isInvalid()) { 262 throw new FileNotFoundException("Invalid file path"); 263 } 264 fd = new FileDescriptor(); 265 fd.attach(this); 266 path = name; 267 open(name, imode); 268 } 269 270 /** 334 private native void open0(String name, int mode) 335 throws FileNotFoundException; 336 337 // wrap native call to allow instrumentation 338 /** 339 * Opens a file and returns the file descriptor. The file is 340 * opened in read-write mode if the O_RDWR bit in {@code mode} 341 * is true, else the file is opened as read-only. 342 * If the {@code name} refers to a directory, an IOException 343 * is thrown. 344 * 345 * @param name the name of the file 346 * @param mode the mode flags, a combination of the O_ constants 347 * defined above 348 */ 349 private void open(String name, int mode) 350 throws FileNotFoundException { 351 open0(name, mode); 352 } 353 354 private native int getPageSize0(); 355 356 private int getPageSize() { 357 if (pageSize == -1) { 358 pageSize = getPageSize0(); 359 } 360 return this.pageSize; 361 } 362 363 // 'Read' primitives 364 365 /** 366 * Reads a byte of data from this file. The byte is returned as an 367 * integer in the range 0 to 255 ({@code 0x00-0x0ff}). This 368 * method blocks if no input is yet available. 369 * <p> 370 * Although {@code RandomAccessFile} is not a subclass of 371 * {@code InputStream}, this method behaves in exactly the same 372 * way as the {@link InputStream#read()} method of 373 * {@code InputStream}. 374 * 375 * @return the next byte of data, or {@code -1} if the end of the 376 * file has been reached. 377 * @exception IOException if an I/O error occurs. Not thrown if 378 * end-of-file has been reached. 379 */ 380 public int read() throws IOException { 381 return read0(); 382 } 383 384 private native int read0() throws IOException; 385 386 /** 387 * Reads a sub array as a sequence of bytes. 388 * @param b the buffer into which the data is read. 389 * @param off the start offset of the data. 390 * @param len the number of bytes to read. 391 * @exception IOException If an I/O error has occurred. 392 */ 393 private native int readBytes(byte b[], int off, int len) throws IOException; 394 395 /** 396 * Reads a sub array as a sequence of bytes with DirectIO. 397 * @param b the buffer into which the data is read. 398 * @param off the start offset of the data. 399 * @param len the number of bytes to read. 400 * @exception IOException If an I/O error has occurred. 401 */ 402 private native int readBytesD(byte b[], int off, int len) throws IOException; 403 404 /** 405 * Reads up to {@code len} bytes of data from this file into an 406 * array of bytes. This method blocks until at least one byte of input 407 * is available. 408 * <p> 409 * Although {@code RandomAccessFile} is not a subclass of 410 * {@code InputStream}, this method behaves in exactly the 411 * same way as the {@link InputStream#read(byte[], int, int)} method of 412 * {@code InputStream}. 413 * 414 * @param b the buffer into which the data is read. 415 * @param off the start offset in array {@code b} 416 * at which the data is written. 417 * @param len the maximum number of bytes read. 418 * @return the total number of bytes read into the buffer, or 419 * {@code -1} if there is no more data because the end of 420 * the file has been reached. 421 * @exception IOException If the first byte cannot be read for any reason 422 * other than end of file, or if the random access file has been closed, or if 423 * some other I/O error occurs. 424 * @exception NullPointerException If {@code b} is {@code null}. 425 * @exception IndexOutOfBoundsException If {@code off} is negative, 426 * {@code len} is negative, or {@code len} is greater than 427 * {@code b.length - off} 428 */ 429 public int read(byte b[], int off, int len) throws IOException { 430 if (direct) { 431 return readBytesD(b, off, len); 432 } 433 return readBytes(b, off, len); 434 } 435 436 /** 437 * Reads up to {@code b.length} bytes of data from this file 438 * into an array of bytes. This method blocks until at least one byte 439 * of input is available. 440 * <p> 441 * Although {@code RandomAccessFile} is not a subclass of 442 * {@code InputStream}, this method behaves in exactly the 443 * same way as the {@link InputStream#read(byte[])} method of 444 * {@code InputStream}. 445 * 446 * @param b the buffer into which the data is read. 447 * @return the total number of bytes read into the buffer, or 448 * {@code -1} if there is no more data because the end of 449 * this file has been reached. 450 * @exception IOException If the first byte cannot be read for any reason 451 * other than end of file, or if the random access file has been closed, or if 452 * some other I/O error occurs. 453 * @exception NullPointerException If {@code b} is {@code null}. 454 */ 455 public int read(byte b[]) throws IOException { 456 if (direct) { 457 return readBytesD(b, 0, b.length); 458 } 459 return readBytes(b, 0, b.length); 460 } 461 462 /** 463 * Reads {@code b.length} bytes from this file into the byte 464 * array, starting at the current file pointer. This method reads 465 * repeatedly from the file until the requested number of bytes are 466 * read. This method blocks until the requested number of bytes are 467 * read, the end of the stream is detected, or an exception is thrown. 468 * 469 * @param b the buffer into which the data is read. 470 * @throws NullPointerException if {@code b} is {@code null}. 471 * @throws EOFException if this file reaches the end before reading 472 * all the bytes. 473 * @throws IOException if an I/O error occurs. 474 */ 475 public final void readFully(byte b[]) throws IOException { 476 readFully(b, 0, b.length); 477 } 478 549 * @param b the {@code byte} to be written. 550 * @exception IOException if an I/O error occurs. 551 */ 552 public void write(int b) throws IOException { 553 write0(b); 554 } 555 556 private native void write0(int b) throws IOException; 557 558 /** 559 * Writes a sub array as a sequence of bytes. 560 * @param b the data to be written 561 562 * @param off the start offset in the data 563 * @param len the number of bytes that are written 564 * @exception IOException If an I/O error has occurred. 565 */ 566 private native void writeBytes(byte b[], int off, int len) throws IOException; 567 568 /** 569 * Writes a sub array as a sequence of bytes with DirectIO. 570 * @param b the data to be written 571 * @param off the start offset in the data 572 * @param len the number of bytes that are written 573 * @exception IOException If an I/O error has occurred. 574 */ 575 private native void writeBytesD(byte b[], int off, int len) throws IOException; 576 577 /** 578 * Writes {@code b.length} bytes from the specified byte array 579 * to this file, starting at the current file pointer. 580 * 581 * @param b the data. 582 * @exception IOException if an I/O error occurs. 583 */ 584 public void write(byte b[]) throws IOException { 585 if (direct) { 586 if((b.length % pageSize != 0) && (getCurrentLocation() % pageSize != 0)) { 587 throw new IOException("In DirectIO mode, the IO size and start point " 588 + "must be aligned with kernel page size " + pageSize + " bytes!"); 589 } else { 590 writeBytesD(b, 0, b.length); 591 } 592 } else { 593 writeBytes(b, 0, b.length); 594 } 595 } 596 597 /** 598 * Writes {@code len} bytes from the specified byte array 599 * starting at offset {@code off} to this file. 600 * 601 * @param b the data. 602 * @param off the start offset in the data. 603 * @param len the number of bytes to write. 604 * @exception IOException if an I/O error occurs. 605 */ 606 public void write(byte b[], int off, int len) throws IOException { 607 if (direct) { 608 if ((len % pageSize != 0) || (getCurrentLocation() % pageSize != 0)) { 609 throw new IOException("In DirectIO mode, the IO size and start point " 610 + "must be aligned with kernel page size " + pageSize + " bytes!"); 611 } else { 612 writeBytesD(b, off, len); 613 } 614 } else { 615 writeBytes(b, off, len); 616 } 617 } 618 619 // 'Random access' stuff 620 621 /** 622 * Returns the current offset in this file. 623 * 624 * @return the offset from the beginning of the file, in bytes, 625 * at which the next read or write occurs. 626 * @exception IOException if an I/O error occurs. 627 */ 628 public native long getFilePointer() throws IOException; 629 630 /** 631 * Sets the file-pointer offset, measured from the beginning of this 632 * file, at which the next read or write occurs. The offset may be 633 * set beyond the end of the file. Setting the offset beyond the end 634 * of the file does not change the file length. The file length will 635 * change only by writing after the offset has been set beyond the end 636 * of the file. 637 * 638 * @param pos the offset position, measured in bytes from the 639 * beginning of the file, at which to set the file 640 * pointer. 641 * @exception IOException if {@code pos} is less than 642 * {@code 0} or if an I/O error occurs. 643 */ 644 public void seek(long pos) throws IOException { 645 if (pos < 0) { 646 throw new IOException("Negative seek offset"); 647 } else { 648 seek0(pos); 649 } 650 } 651 652 private native void seek0(long pos) throws IOException; 653 654 private long getCurrentLocation() throws IOException { 655 return getCurrentLocation0(); 656 } 657 658 private native long getCurrentLocation0() throws IOException; 659 660 /** 661 * Returns the length of this file. 662 * 663 * @return the length of this file, measured in bytes. 664 * @exception IOException if an I/O error occurs. 665 */ 666 public native long length() throws IOException; 667 668 /** 669 * Sets the length of this file. 670 * 671 * <p> If the present length of the file as returned by the 672 * {@code length} method is greater than the {@code newLength} 673 * argument then the file will be truncated. In this case, if the file 674 * offset as returned by the {@code getFilePointer} method is greater 675 * than {@code newLength} then after this method returns the offset 676 * will be equal to {@code newLength}. 677 * 678 * <p> If the present length of the file as returned by the |