1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.io; 19 20import android.system.ErrnoException; 21import dalvik.system.CloseGuard; 22import java.nio.ByteOrder; 23import java.nio.channels.FileChannel; 24import java.nio.charset.ModifiedUtf8; 25import java.nio.NioUtils; 26import java.util.Arrays; 27import libcore.io.IoBridge; 28import libcore.io.Libcore; 29import libcore.io.Memory; 30import libcore.io.SizeOf; 31import static android.system.OsConstants.*; 32 33/** 34 * Allows reading from and writing to a file in a random-access manner. This is 35 * different from the uni-directional sequential access that a 36 * {@link FileInputStream} or {@link FileOutputStream} provides. If the file is 37 * opened in read/write mode, write operations are available as well. The 38 * position of the next read or write operation can be moved forwards and 39 * backwards after every operation. 40 */ 41public class RandomAccessFile implements DataInput, DataOutput, Closeable { 42 /** 43 * The FileDescriptor representing this RandomAccessFile. 44 */ 45 private FileDescriptor fd; 46 47 private boolean syncMetadata = false; 48 49 // The unique file channel associated with this FileInputStream (lazily 50 // initialized). 51 private FileChannel channel; 52 53 private int mode; 54 55 private final CloseGuard guard = CloseGuard.get(); 56 57 private final byte[] scratch = new byte[8]; 58 59 /** 60 * Constructs a new {@code RandomAccessFile} based on {@code file} and opens 61 * it according to the access string in {@code mode}. 62 * <p><a id="accessmode"/> 63 * {@code mode} may have one of following values: 64 * <table border="0"> 65 * <tr> 66 * <td>{@code "r"}</td> 67 * <td>The file is opened in read-only mode. An {@code IOException} is 68 * thrown if any of the {@code write} methods is called.</td> 69 * </tr> 70 * <tr> 71 * <td>{@code "rw"}</td> 72 * <td>The file is opened for reading and writing. If the file does not 73 * exist, it will be created.</td> 74 * </tr> 75 * <tr> 76 * <td>{@code "rws"}</td> 77 * <td>The file is opened for reading and writing. Every change of the 78 * file's content or metadata must be written synchronously to the target 79 * device.</td> 80 * </tr> 81 * <tr> 82 * <td>{@code "rwd"}</td> 83 * <td>The file is opened for reading and writing. Every change of the 84 * file's content must be written synchronously to the target device.</td> 85 * </tr> 86 * </table> 87 * 88 * @param file 89 * the file to open. 90 * @param mode 91 * the file access <a href="#accessmode">mode</a>, either {@code 92 * "r"}, {@code "rw"}, {@code "rws"} or {@code "rwd"}. 93 * @throws FileNotFoundException 94 * if the file cannot be opened or created according to {@code 95 * mode}. 96 * @throws IllegalArgumentException 97 * if {@code mode} is not {@code "r"}, {@code "rw"}, {@code 98 * "rws"} or {@code "rwd"}. 99 */ 100 public RandomAccessFile(File file, String mode) throws FileNotFoundException { 101 int flags; 102 if (mode.equals("r")) { 103 flags = O_RDONLY; 104 } else if (mode.equals("rw") || mode.equals("rws") || mode.equals("rwd")) { 105 flags = O_RDWR | O_CREAT; 106 if (mode.equals("rws")) { 107 // Sync file and metadata with every write 108 syncMetadata = true; 109 } else if (mode.equals("rwd")) { 110 // Sync file, but not necessarily metadata 111 flags |= O_SYNC; 112 } 113 } else { 114 throw new IllegalArgumentException("Invalid mode: " + mode); 115 } 116 this.mode = flags; 117 this.fd = IoBridge.open(file.getPath(), flags); 118 119 // if we are in "rws" mode, attempt to sync file+metadata 120 if (syncMetadata) { 121 try { 122 fd.sync(); 123 } catch (IOException e) { 124 // Ignored 125 } 126 } 127 guard.open("close"); 128 } 129 130 /** 131 * Constructs a new {@code RandomAccessFile} based on the file named {@code 132 * fileName} and opens it according to the access string in {@code mode}. 133 * The file path may be specified absolutely or relative to the system 134 * property {@code "user.dir"}. 135 * 136 * @param fileName 137 * the name of the file to open. 138 * @param mode 139 * the file access <a href="#accessmode">mode</a>, either {@code 140 * "r"}, {@code "rw"}, {@code "rws"} or {@code "rwd"}. 141 * @throws FileNotFoundException 142 * if the file cannot be opened or created according to {@code 143 * mode}. 144 * @throws IllegalArgumentException 145 * if {@code mode} is not {@code "r"}, {@code "rw"}, {@code 146 * "rws"} or {@code "rwd"}. 147 */ 148 public RandomAccessFile(String fileName, String mode) throws FileNotFoundException { 149 this(new File(fileName), mode); 150 } 151 152 /** 153 * Closes this file. 154 * 155 * @throws IOException 156 * if an error occurs while closing this file. 157 */ 158 public void close() throws IOException { 159 guard.close(); 160 synchronized (this) { 161 if (channel != null && channel.isOpen()) { 162 channel.close(); 163 } 164 IoBridge.closeAndSignalBlockedThreads(fd); 165 } 166 } 167 168 @Override protected void finalize() throws Throwable { 169 try { 170 if (guard != null) { 171 guard.warnIfOpen(); 172 } 173 close(); 174 } finally { 175 super.finalize(); 176 } 177 } 178 179 /** 180 * Gets this file's {@link FileChannel} object. 181 * <p> 182 * The file channel's {@link FileChannel#position() position} is the same 183 * as this file's file pointer offset (see {@link #getFilePointer()}). Any 184 * changes made to this file's file pointer offset are also visible in the 185 * file channel's position and vice versa. 186 * 187 * Closing the channel closes the RandomAccessFile as well. The instance 188 * of FileChannel returned is always the same even if the RandomAccessFile 189 * or the FileChannel have been closed. 190 * 191 * @return this file's file channel instance. 192 */ 193 public final synchronized FileChannel getChannel() { 194 if(channel == null) { 195 channel = NioUtils.newFileChannel(this, fd, mode); 196 } 197 return channel; 198 } 199 200 /** 201 * Gets this file's {@link FileDescriptor}. This represents the operating 202 * system resource for this random access file. 203 * 204 * @return this file's file descriptor object. 205 * @throws IOException 206 * if an error occurs while getting the file descriptor of this 207 * file. 208 */ 209 public final FileDescriptor getFD() throws IOException { 210 return fd; 211 } 212 213 /** 214 * Gets the current position within this file. All reads and 215 * writes take place at the current file pointer position. 216 * 217 * @return the current offset in bytes from the beginning of the file. 218 * 219 * @throws IOException 220 * if an error occurs while getting the file pointer of this 221 * file. 222 */ 223 public long getFilePointer() throws IOException { 224 try { 225 return Libcore.os.lseek(fd, 0L, SEEK_CUR); 226 } catch (ErrnoException errnoException) { 227 throw errnoException.rethrowAsIOException(); 228 } 229 } 230 231 /** 232 * Returns the length of this file in bytes. 233 * 234 * @return the file's length in bytes. 235 * @throws IOException 236 * if this file is closed or some other I/O error occurs. 237 */ 238 public long length() throws IOException { 239 try { 240 return Libcore.os.fstat(fd).st_size; 241 } catch (ErrnoException errnoException) { 242 throw errnoException.rethrowAsIOException(); 243 } 244 } 245 246 /** 247 * Reads a single byte from the current position in this file and returns it 248 * as an integer in the range from 0 to 255. Returns -1 if the end of the 249 * file has been reached. Blocks until one byte has been read, the end of 250 * the file is detected, or an exception is thrown. 251 * 252 * @return the byte read or -1 if the end of the file has been reached. 253 * @throws IOException 254 * if this file is closed or another I/O error occurs. 255 */ 256 public int read() throws IOException { 257 return (read(scratch, 0, 1) != -1) ? scratch[0] & 0xff : -1; 258 } 259 260 /** 261 * Reads bytes from the current position in this file and stores them in the 262 * byte array {@code buffer}. The maximum number of bytes read corresponds 263 * to the size of {@code buffer}. Blocks until at least one byte has been 264 * read, the end of the file is detected, or an exception is thrown. 265 * Returns the number of bytes actually read or -1 if the end of the file 266 * has been reached. See also {@link #readFully}. 267 * 268 * @throws IOException 269 * if this file is closed or another I/O error occurs. 270 */ 271 public int read(byte[] buffer) throws IOException { 272 return read(buffer, 0, buffer.length); 273 } 274 275 /** 276 * Reads up to {@code byteCount} bytes from the current position in this file 277 * and stores them in the byte array {@code buffer} starting at {@code 278 * byteOffset}. Blocks until at least one byte has been 279 * read, the end of the file is detected, or an exception is thrown. 280 * Returns the number of bytes actually read or -1 if the end of the stream has been reached. 281 * See also {@link #readFully}. 282 * 283 * @throws IndexOutOfBoundsException 284 * if {@code byteOffset < 0 || byteCount < 0 || byteOffset + byteCount > buffer.length}. 285 * @throws IOException 286 * if this file is closed or another I/O error occurs. 287 */ 288 public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { 289 return IoBridge.read(fd, buffer, byteOffset, byteCount); 290 } 291 292 /** 293 * Reads a boolean from the current position in this file. Blocks until one 294 * byte has been read, the end of the file is reached or an exception is 295 * thrown. 296 * 297 * @return the next boolean value from this file. 298 * @throws EOFException 299 * if the end of this file is detected. 300 * @throws IOException 301 * if this file is closed or another I/O error occurs. 302 * @see #writeBoolean(boolean) 303 */ 304 public final boolean readBoolean() throws IOException { 305 int temp = this.read(); 306 if (temp < 0) { 307 throw new EOFException(); 308 } 309 return temp != 0; 310 } 311 312 /** 313 * Reads an 8-bit byte from the current position in this file. Blocks until 314 * one byte has been read, the end of the file is reached or an exception is 315 * thrown. 316 * 317 * @return the next signed 8-bit byte value from this file. 318 * @throws EOFException 319 * if the end of this file is detected. 320 * @throws IOException 321 * if this file is closed or another I/O error occurs. 322 * @see #writeBoolean(boolean) 323 */ 324 public final byte readByte() throws IOException { 325 int temp = this.read(); 326 if (temp < 0) { 327 throw new EOFException(); 328 } 329 return (byte) temp; 330 } 331 332 /** 333 * Reads a big-endian 16-bit character from the current position in this file. Blocks until 334 * two bytes have been read, the end of the file is reached or an exception is 335 * thrown. 336 * 337 * @return the next char value from this file. 338 * @throws EOFException 339 * if the end of this file is detected. 340 * @throws IOException 341 * if this file is closed or another I/O error occurs. 342 * @see #writeChar(int) 343 */ 344 public final char readChar() throws IOException { 345 return (char) readShort(); 346 } 347 348 /** 349 * Reads a big-endian 64-bit double from the current position in this file. Blocks 350 * until eight bytes have been read, the end of the file is reached or an 351 * exception is thrown. 352 * 353 * @return the next double value from this file. 354 * @throws EOFException 355 * if the end of this file is detected. 356 * @throws IOException 357 * if this file is closed or another I/O error occurs. 358 * @see #writeDouble(double) 359 */ 360 public final double readDouble() throws IOException { 361 return Double.longBitsToDouble(readLong()); 362 } 363 364 /** 365 * Reads a big-endian 32-bit float from the current position in this file. Blocks 366 * until four bytes have been read, the end of the file is reached or an 367 * exception is thrown. 368 * 369 * @return the next float value from this file. 370 * @throws EOFException 371 * if the end of this file is detected. 372 * @throws IOException 373 * if this file is closed or another I/O error occurs. 374 * @see #writeFloat(float) 375 */ 376 public final float readFloat() throws IOException { 377 return Float.intBitsToFloat(readInt()); 378 } 379 380 /** 381 * Equivalent to {@code readFully(dst, 0, dst.length);}. 382 */ 383 public final void readFully(byte[] dst) throws IOException { 384 readFully(dst, 0, dst.length); 385 } 386 387 /** 388 * Reads {@code byteCount} bytes from this stream and stores them in the byte 389 * array {@code dst} starting at {@code offset}. If {@code byteCount} is zero, then this 390 * method returns without reading any bytes. Otherwise, this method blocks until 391 * {@code byteCount} bytes have been read. If insufficient bytes are available, 392 * {@code EOFException} is thrown. If an I/O error occurs, {@code IOException} is 393 * thrown. When an exception is thrown, some bytes may have been consumed from the stream 394 * and written into the array. 395 * 396 * @param dst 397 * the byte array into which the data is read. 398 * @param offset 399 * the offset in {@code dst} at which to store the bytes. 400 * @param byteCount 401 * the number of bytes to read. 402 * @throws EOFException 403 * if the end of the source stream is reached before enough 404 * bytes have been read. 405 * @throws IndexOutOfBoundsException 406 * if {@code offset < 0} or {@code byteCount < 0}, or 407 * {@code offset + byteCount > dst.length}. 408 * @throws IOException 409 * if a problem occurs while reading from this stream. 410 * @throws NullPointerException 411 * if {@code dst} is null. 412 */ 413 public final void readFully(byte[] dst, int offset, int byteCount) throws IOException { 414 Arrays.checkOffsetAndCount(dst.length, offset, byteCount); 415 while (byteCount > 0) { 416 int result = read(dst, offset, byteCount); 417 if (result < 0) { 418 throw new EOFException(); 419 } 420 offset += result; 421 byteCount -= result; 422 } 423 } 424 425 /** 426 * Reads a big-endian 32-bit integer from the current position in this file. Blocks 427 * until four bytes have been read, the end of the file is reached or an 428 * exception is thrown. 429 * 430 * @return the next int value from this file. 431 * @throws EOFException 432 * if the end of this file is detected. 433 * @throws IOException 434 * if this file is closed or another I/O error occurs. 435 * @see #writeInt(int) 436 */ 437 public final int readInt() throws IOException { 438 readFully(scratch, 0, SizeOf.INT); 439 return Memory.peekInt(scratch, 0, ByteOrder.BIG_ENDIAN); 440 } 441 442 /** 443 * Reads a line of text form the current position in this file. A line is 444 * represented by zero or more characters followed by {@code '\n'}, {@code 445 * '\r'}, {@code "\r\n"} or the end of file marker. The string does not 446 * include the line terminating sequence. 447 * <p> 448 * Blocks until a line terminating sequence has been read, the end of the 449 * file is reached or an exception is thrown. 450 * 451 * @return the contents of the line or {@code null} if no characters have 452 * been read before the end of the file has been reached. 453 * @throws IOException 454 * if this file is closed or another I/O error occurs. 455 */ 456 public final String readLine() throws IOException { 457 StringBuilder line = new StringBuilder(80); // Typical line length 458 boolean foundTerminator = false; 459 long unreadPosition = 0; 460 while (true) { 461 int nextByte = read(); 462 switch (nextByte) { 463 case -1: 464 return line.length() != 0 ? line.toString() : null; 465 case (byte) '\r': 466 if (foundTerminator) { 467 seek(unreadPosition); 468 return line.toString(); 469 } 470 foundTerminator = true; 471 /* Have to be able to peek ahead one byte */ 472 unreadPosition = getFilePointer(); 473 break; 474 case (byte) '\n': 475 return line.toString(); 476 default: 477 if (foundTerminator) { 478 seek(unreadPosition); 479 return line.toString(); 480 } 481 line.append((char) nextByte); 482 } 483 } 484 } 485 486 /** 487 * Reads a big-endian 64-bit long from the current position in this file. Blocks until 488 * eight bytes have been read, the end of the file is reached or an 489 * exception is thrown. 490 * 491 * @return the next long value from this file. 492 * @throws EOFException 493 * if the end of this file is detected. 494 * @throws IOException 495 * if this file is closed or another I/O error occurs. 496 * @see #writeLong(long) 497 */ 498 public final long readLong() throws IOException { 499 readFully(scratch, 0, SizeOf.LONG); 500 return Memory.peekLong(scratch, 0, ByteOrder.BIG_ENDIAN); 501 } 502 503 /** 504 * Reads a big-endian 16-bit short from the current position in this file. Blocks until 505 * two bytes have been read, the end of the file is reached or an exception 506 * is thrown. 507 * 508 * @return the next short value from this file. 509 * @throws EOFException 510 * if the end of this file is detected. 511 * @throws IOException 512 * if this file is closed or another I/O error occurs. 513 * @see #writeShort(int) 514 */ 515 public final short readShort() throws IOException { 516 readFully(scratch, 0, SizeOf.SHORT); 517 return Memory.peekShort(scratch, 0, ByteOrder.BIG_ENDIAN); 518 } 519 520 /** 521 * Reads an unsigned 8-bit byte from the current position in this file and 522 * returns it as an integer. Blocks until one byte has been read, the end of 523 * the file is reached or an exception is thrown. 524 * 525 * @return the next unsigned byte value from this file as an int. 526 * @throws EOFException 527 * if the end of this file is detected. 528 * @throws IOException 529 * if this file is closed or another I/O error occurs. 530 * @see #writeByte(int) 531 */ 532 public final int readUnsignedByte() throws IOException { 533 int temp = this.read(); 534 if (temp < 0) { 535 throw new EOFException(); 536 } 537 return temp; 538 } 539 540 /** 541 * Reads an unsigned big-endian 16-bit short from the current position in this file and 542 * returns it as an integer. Blocks until two bytes have been read, the end of 543 * the file is reached or an exception is thrown. 544 * 545 * @return the next unsigned short value from this file as an int. 546 * @throws EOFException 547 * if the end of this file is detected. 548 * @throws IOException 549 * if this file is closed or another I/O error occurs. 550 * @see #writeShort(int) 551 */ 552 public final int readUnsignedShort() throws IOException { 553 return ((int) readShort()) & 0xffff; 554 } 555 556 /** 557 * Reads a string that is encoded in {@link DataInput modified UTF-8} from 558 * this file. The number of bytes that must be read for the complete string 559 * is determined by the first two bytes read from the file. Blocks until all 560 * required bytes have been read, the end of the file is reached or an 561 * exception is thrown. 562 * 563 * @return the next string encoded in {@link DataInput modified UTF-8} from 564 * this file. 565 * @throws EOFException 566 * if the end of this file is detected. 567 * @throws IOException 568 * if this file is closed or another I/O error occurs. 569 * @throws UTFDataFormatException 570 * if the bytes read cannot be decoded into a character string. 571 * @see #writeUTF(String) 572 */ 573 public final String readUTF() throws IOException { 574 int utfSize = readUnsignedShort(); 575 if (utfSize == 0) { 576 return ""; 577 } 578 byte[] buf = new byte[utfSize]; 579 if (read(buf, 0, buf.length) != buf.length) { 580 throw new EOFException(); 581 } 582 return ModifiedUtf8.decode(buf, new char[utfSize], 0, utfSize); 583 } 584 585 /** 586 * Moves this file's file pointer to a new position, from where following 587 * {@code read}, {@code write} or {@code skip} operations are done. The 588 * position may be greater than the current length of the file, but the 589 * file's length will only change if the moving of the pointer is followed 590 * by a {@code write} operation. 591 * 592 * @param offset 593 * the new file pointer position. 594 * @throws IOException 595 * if this file is closed, {@code pos < 0} or another I/O error 596 * occurs. 597 */ 598 public void seek(long offset) throws IOException { 599 if (offset < 0) { 600 throw new IOException("offset < 0: " + offset); 601 } 602 try { 603 Libcore.os.lseek(fd, offset, SEEK_SET); 604 } catch (ErrnoException errnoException) { 605 throw errnoException.rethrowAsIOException(); 606 } 607 } 608 609 /** 610 * Sets the length of this file to {@code newLength}. If the current file is 611 * smaller, it is expanded but the contents from the previous end of the 612 * file to the new end are undefined. The file is truncated if its current 613 * size is bigger than {@code newLength}. If the current file pointer 614 * position is in the truncated part, it is set to the end of the file. 615 * 616 * @param newLength 617 * the new file length in bytes. 618 * @throws IllegalArgumentException 619 * if {@code newLength < 0}. 620 * @throws IOException 621 * if this file is closed or another I/O error occurs. 622 */ 623 public void setLength(long newLength) throws IOException { 624 if (newLength < 0) { 625 throw new IllegalArgumentException("newLength < 0"); 626 } 627 try { 628 Libcore.os.ftruncate(fd, newLength); 629 } catch (ErrnoException errnoException) { 630 throw errnoException.rethrowAsIOException(); 631 } 632 633 long filePointer = getFilePointer(); 634 if (filePointer > newLength) { 635 seek(newLength); 636 } 637 638 // if we are in "rws" mode, attempt to sync file+metadata 639 if (syncMetadata) { 640 fd.sync(); 641 } 642 } 643 644 /** 645 * Skips over {@code count} bytes in this file. Less than {@code count} 646 * bytes are skipped if the end of the file is reached or an exception is 647 * thrown during the operation. Nothing is done if {@code count} is 648 * negative. 649 * 650 * @param count 651 * the number of bytes to skip. 652 * @return the number of bytes actually skipped. 653 * @throws IOException 654 * if this file is closed or another I/O error occurs. 655 */ 656 public int skipBytes(int count) throws IOException { 657 if (count > 0) { 658 long currentPos = getFilePointer(), eof = length(); 659 int newCount = (int) ((currentPos + count > eof) ? eof - currentPos : count); 660 seek(currentPos + newCount); 661 return newCount; 662 } 663 return 0; 664 } 665 666 /** 667 * Writes the entire contents of the byte array {@code buffer} to this file, 668 * starting at the current file pointer. 669 * 670 * @param buffer 671 * the buffer to write. 672 * @throws IOException 673 * if an I/O error occurs while writing to this file. 674 */ 675 public void write(byte[] buffer) throws IOException { 676 write(buffer, 0, buffer.length); 677 } 678 679 /** 680 * Writes {@code byteCount} bytes from the byte array {@code buffer} to this 681 * file, starting at the current file pointer and using {@code byteOffset} as 682 * the first position within {@code buffer} to get bytes. 683 * 684 * @throws IndexOutOfBoundsException 685 * if {@code byteCount < 0}, {@code byteOffset < 0} or {@code byteCount + 686 * byteOffset} is greater than the size of {@code buffer}. 687 * @throws IOException 688 * if an I/O error occurs while writing to this file. 689 */ 690 public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException { 691 IoBridge.write(fd, buffer, byteOffset, byteCount); 692 // if we are in "rws" mode, attempt to sync file+metadata 693 if (syncMetadata) { 694 fd.sync(); 695 } 696 } 697 698 /** 699 * Writes a byte to this file, starting at the current file pointer. Only 700 * the least significant byte of the integer {@code oneByte} is written. 701 * 702 * @param oneByte 703 * the byte to write to this file. 704 * @throws IOException 705 * if this file is closed or another I/O error occurs. 706 * @see #read() 707 */ 708 public void write(int oneByte) throws IOException { 709 scratch[0] = (byte) (oneByte & 0xff); 710 write(scratch, 0, 1); 711 } 712 713 /** 714 * Writes a boolean to this file as a single byte (1 for true, 0 for false), starting at the 715 * current file pointer. 716 * 717 * @param val 718 * the boolean to write to this file. 719 * @throws IOException 720 * if this file is closed or another I/O error occurs. 721 * @see #readBoolean() 722 */ 723 public final void writeBoolean(boolean val) throws IOException { 724 write(val ? 1 : 0); 725 } 726 727 /** 728 * Writes an 8-bit byte to this file, starting at the current file pointer. 729 * Only the least significant byte of the integer {@code val} is written. 730 * 731 * @param val 732 * the byte to write to this file. 733 * @throws IOException 734 * if this file is closed or another I/O error occurs. 735 * @see #readByte() 736 * @see #readUnsignedByte() 737 */ 738 public final void writeByte(int val) throws IOException { 739 write(val & 0xFF); 740 } 741 742 /** 743 * Writes the low order 8-bit bytes from a string to this file, starting at 744 * the current file pointer. 745 * 746 * @param str 747 * the string containing the bytes to write to this file 748 * @throws IOException 749 * if an I/O error occurs while writing to this file. 750 */ 751 public final void writeBytes(String str) throws IOException { 752 byte[] bytes = new byte[str.length()]; 753 for (int index = 0; index < str.length(); index++) { 754 bytes[index] = (byte) (str.charAt(index) & 0xFF); 755 } 756 write(bytes); 757 } 758 759 /** 760 * Writes a big-endian 16-bit character to this file, starting at the current file 761 * pointer. Only the two least significant bytes of the integer {@code val} 762 * are written, with the high byte first. 763 * 764 * @param val 765 * the char to write to this file. 766 * @throws IOException 767 * if an I/O error occurs while writing to this file. 768 * @see #readChar() 769 */ 770 public final void writeChar(int val) throws IOException { 771 writeShort(val); 772 } 773 774 /** 775 * Writes big-endian 16-bit characters from {@code str} to this file, starting at the 776 * current file pointer. 777 * 778 * @param str 779 * the string to write to this file. 780 * @throws IOException 781 * if an I/O error occurs while writing to this file. 782 * @see #readChar() 783 */ 784 public final void writeChars(String str) throws IOException { 785 write(str.getBytes("UTF-16BE")); 786 } 787 788 /** 789 * Writes a big-endian 64-bit double to this file, starting at the current file 790 * pointer. The bytes are those returned by 791 * {@link Double#doubleToLongBits(double)}, meaning a canonical NaN is used. 792 * 793 * @param val 794 * the double to write to this file. 795 * @throws IOException 796 * if an I/O error occurs while writing to this file. 797 * @see #readDouble() 798 */ 799 public final void writeDouble(double val) throws IOException { 800 writeLong(Double.doubleToLongBits(val)); 801 } 802 803 /** 804 * Writes a big-endian 32-bit float to this file, starting at the current file pointer. 805 * The bytes are those returned by {@link Float#floatToIntBits(float)}, meaning a canonical NaN 806 * is used. 807 * 808 * @param val 809 * the float to write to this file. 810 * @throws IOException 811 * if an I/O error occurs while writing to this file. 812 * @see #readFloat() 813 */ 814 public final void writeFloat(float val) throws IOException { 815 writeInt(Float.floatToIntBits(val)); 816 } 817 818 /** 819 * Writes a big-endian 32-bit integer to this file, starting at the current file 820 * pointer. 821 * 822 * @param val 823 * the int to write to this file. 824 * @throws IOException 825 * if an I/O error occurs while writing to this file. 826 * @see #readInt() 827 */ 828 public final void writeInt(int val) throws IOException { 829 Memory.pokeInt(scratch, 0, val, ByteOrder.BIG_ENDIAN); 830 write(scratch, 0, SizeOf.INT); 831 } 832 833 /** 834 * Writes a big-endian 64-bit long to this file, starting at the current file 835 * pointer. 836 * 837 * @param val 838 * the long to write to this file. 839 * @throws IOException 840 * if an I/O error occurs while writing to this file. 841 * @see #readLong() 842 */ 843 public final void writeLong(long val) throws IOException { 844 Memory.pokeLong(scratch, 0, val, ByteOrder.BIG_ENDIAN); 845 write(scratch, 0, SizeOf.LONG); 846 } 847 848 /** 849 * Writes a big-endian 16-bit short to this file, starting at the current file 850 * pointer. Only the two least significant bytes of the integer {@code val} 851 * are written. 852 * 853 * @param val 854 * the short to write to this file. 855 * @throws IOException 856 * if an I/O error occurs while writing to this file. 857 * @see #readShort() 858 * @see DataInput#readUnsignedShort() 859 */ 860 public final void writeShort(int val) throws IOException { 861 Memory.pokeShort(scratch, 0, (short) val, ByteOrder.BIG_ENDIAN); 862 write(scratch, 0, SizeOf.SHORT); 863 } 864 865 /** 866 * Writes a string encoded with {@link DataInput modified UTF-8} to this 867 * file, starting at the current file pointer. 868 * 869 * @param str 870 * the string to write in {@link DataInput modified UTF-8} 871 * format. 872 * @throws IOException 873 * if an I/O error occurs while writing to this file. 874 * @throws UTFDataFormatException 875 * if the encoded string is longer than 65535 bytes. 876 * @see #readUTF() 877 */ 878 public final void writeUTF(String str) throws IOException { 879 write(ModifiedUtf8.encode(str)); 880 } 881} 882