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 channel = null; 164 } 165 IoBridge.closeAndSignalBlockedThreads(fd); 166 } 167 } 168 169 @Override protected void finalize() throws Throwable { 170 try { 171 if (guard != null) { 172 guard.warnIfOpen(); 173 } 174 close(); 175 } finally { 176 super.finalize(); 177 } 178 } 179 180 /** 181 * Gets this file's {@link FileChannel} object. 182 * <p> 183 * The file channel's {@link FileChannel#position() position} is the same 184 * as this file's file pointer offset (see {@link #getFilePointer()}). Any 185 * changes made to this file's file pointer offset are also visible in the 186 * file channel's position and vice versa. 187 * 188 * @return this file's file channel instance. 189 */ 190 public final synchronized FileChannel getChannel() { 191 if(channel == null) { 192 channel = NioUtils.newFileChannel(this, fd, mode); 193 } 194 return channel; 195 } 196 197 /** 198 * Gets this file's {@link FileDescriptor}. This represents the operating 199 * system resource for this random access file. 200 * 201 * @return this file's file descriptor object. 202 * @throws IOException 203 * if an error occurs while getting the file descriptor of this 204 * file. 205 */ 206 public final FileDescriptor getFD() throws IOException { 207 return fd; 208 } 209 210 /** 211 * Gets the current position within this file. All reads and 212 * writes take place at the current file pointer position. 213 * 214 * @return the current offset in bytes from the beginning of the file. 215 * 216 * @throws IOException 217 * if an error occurs while getting the file pointer of this 218 * file. 219 */ 220 public long getFilePointer() throws IOException { 221 try { 222 return Libcore.os.lseek(fd, 0L, SEEK_CUR); 223 } catch (ErrnoException errnoException) { 224 throw errnoException.rethrowAsIOException(); 225 } 226 } 227 228 /** 229 * Returns the length of this file in bytes. 230 * 231 * @return the file's length in bytes. 232 * @throws IOException 233 * if this file is closed or some other I/O error occurs. 234 */ 235 public long length() throws IOException { 236 try { 237 return Libcore.os.fstat(fd).st_size; 238 } catch (ErrnoException errnoException) { 239 throw errnoException.rethrowAsIOException(); 240 } 241 } 242 243 /** 244 * Reads a single byte from the current position in this file and returns it 245 * as an integer in the range from 0 to 255. Returns -1 if the end of the 246 * file has been reached. Blocks until one byte has been read, the end of 247 * the file is detected, or an exception is thrown. 248 * 249 * @return the byte read or -1 if the end of the file has been reached. 250 * @throws IOException 251 * if this file is closed or another I/O error occurs. 252 */ 253 public int read() throws IOException { 254 return (read(scratch, 0, 1) != -1) ? scratch[0] & 0xff : -1; 255 } 256 257 /** 258 * Reads bytes from the current position in this file and stores them in the 259 * byte array {@code buffer}. The maximum number of bytes read corresponds 260 * to the size of {@code buffer}. Blocks until at least one byte has been 261 * read, the end of the file is detected, or an exception is thrown. 262 * Returns the number of bytes actually read or -1 if the end of the file 263 * has been reached. See also {@link #readFully}. 264 * 265 * @throws IOException 266 * if this file is closed or another I/O error occurs. 267 */ 268 public int read(byte[] buffer) throws IOException { 269 return read(buffer, 0, buffer.length); 270 } 271 272 /** 273 * Reads up to {@code byteCount} bytes from the current position in this file 274 * and stores them in the byte array {@code buffer} starting at {@code 275 * byteOffset}. Blocks until at least one byte has been 276 * read, the end of the file is detected, or an exception is thrown. 277 * Returns the number of bytes actually read or -1 if the end of the stream has been reached. 278 * See also {@link #readFully}. 279 * 280 * @throws IndexOutOfBoundsException 281 * if {@code byteOffset < 0 || byteCount < 0 || byteOffset + byteCount > buffer.length}. 282 * @throws IOException 283 * if this file is closed or another I/O error occurs. 284 */ 285 public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { 286 return IoBridge.read(fd, buffer, byteOffset, byteCount); 287 } 288 289 /** 290 * Reads a boolean from the current position in this file. Blocks until one 291 * byte has been read, the end of the file is reached or an exception is 292 * thrown. 293 * 294 * @return the next boolean value from this file. 295 * @throws EOFException 296 * if the end of this file is detected. 297 * @throws IOException 298 * if this file is closed or another I/O error occurs. 299 * @see #writeBoolean(boolean) 300 */ 301 public final boolean readBoolean() throws IOException { 302 int temp = this.read(); 303 if (temp < 0) { 304 throw new EOFException(); 305 } 306 return temp != 0; 307 } 308 309 /** 310 * Reads an 8-bit byte from the current position in this file. Blocks until 311 * one byte has been read, the end of the file is reached or an exception is 312 * thrown. 313 * 314 * @return the next signed 8-bit byte value from this file. 315 * @throws EOFException 316 * if the end of this file is detected. 317 * @throws IOException 318 * if this file is closed or another I/O error occurs. 319 * @see #writeBoolean(boolean) 320 */ 321 public final byte readByte() throws IOException { 322 int temp = this.read(); 323 if (temp < 0) { 324 throw new EOFException(); 325 } 326 return (byte) temp; 327 } 328 329 /** 330 * Reads a big-endian 16-bit character from the current position in this file. Blocks until 331 * two bytes have been read, the end of the file is reached or an exception is 332 * thrown. 333 * 334 * @return the next char value from this file. 335 * @throws EOFException 336 * if the end of this file is detected. 337 * @throws IOException 338 * if this file is closed or another I/O error occurs. 339 * @see #writeChar(int) 340 */ 341 public final char readChar() throws IOException { 342 return (char) readShort(); 343 } 344 345 /** 346 * Reads a big-endian 64-bit double from the current position in this file. Blocks 347 * until eight bytes have been read, the end of the file is reached or an 348 * exception is thrown. 349 * 350 * @return the next double value from this file. 351 * @throws EOFException 352 * if the end of this file is detected. 353 * @throws IOException 354 * if this file is closed or another I/O error occurs. 355 * @see #writeDouble(double) 356 */ 357 public final double readDouble() throws IOException { 358 return Double.longBitsToDouble(readLong()); 359 } 360 361 /** 362 * Reads a big-endian 32-bit float from the current position in this file. Blocks 363 * until four bytes have been read, the end of the file is reached or an 364 * exception is thrown. 365 * 366 * @return the next float value from this file. 367 * @throws EOFException 368 * if the end of this file is detected. 369 * @throws IOException 370 * if this file is closed or another I/O error occurs. 371 * @see #writeFloat(float) 372 */ 373 public final float readFloat() throws IOException { 374 return Float.intBitsToFloat(readInt()); 375 } 376 377 /** 378 * Equivalent to {@code readFully(dst, 0, dst.length);}. 379 */ 380 public final void readFully(byte[] dst) throws IOException { 381 readFully(dst, 0, dst.length); 382 } 383 384 /** 385 * Reads {@code byteCount} bytes from this stream and stores them in the byte 386 * array {@code dst} starting at {@code offset}. If {@code byteCount} is zero, then this 387 * method returns without reading any bytes. Otherwise, this method blocks until 388 * {@code byteCount} bytes have been read. If insufficient bytes are available, 389 * {@code EOFException} is thrown. If an I/O error occurs, {@code IOException} is 390 * thrown. When an exception is thrown, some bytes may have been consumed from the stream 391 * and written into the array. 392 * 393 * @param dst 394 * the byte array into which the data is read. 395 * @param offset 396 * the offset in {@code dst} at which to store the bytes. 397 * @param byteCount 398 * the number of bytes to read. 399 * @throws EOFException 400 * if the end of the source stream is reached before enough 401 * bytes have been read. 402 * @throws IndexOutOfBoundsException 403 * if {@code offset < 0} or {@code byteCount < 0}, or 404 * {@code offset + byteCount > dst.length}. 405 * @throws IOException 406 * if a problem occurs while reading from this stream. 407 * @throws NullPointerException 408 * if {@code dst} is null. 409 */ 410 public final void readFully(byte[] dst, int offset, int byteCount) throws IOException { 411 Arrays.checkOffsetAndCount(dst.length, offset, byteCount); 412 while (byteCount > 0) { 413 int result = read(dst, offset, byteCount); 414 if (result < 0) { 415 throw new EOFException(); 416 } 417 offset += result; 418 byteCount -= result; 419 } 420 } 421 422 /** 423 * Reads a big-endian 32-bit integer from the current position in this file. Blocks 424 * until four bytes have been read, the end of the file is reached or an 425 * exception is thrown. 426 * 427 * @return the next int value from this file. 428 * @throws EOFException 429 * if the end of this file is detected. 430 * @throws IOException 431 * if this file is closed or another I/O error occurs. 432 * @see #writeInt(int) 433 */ 434 public final int readInt() throws IOException { 435 readFully(scratch, 0, SizeOf.INT); 436 return Memory.peekInt(scratch, 0, ByteOrder.BIG_ENDIAN); 437 } 438 439 /** 440 * Reads a line of text form the current position in this file. A line is 441 * represented by zero or more characters followed by {@code '\n'}, {@code 442 * '\r'}, {@code "\r\n"} or the end of file marker. The string does not 443 * include the line terminating sequence. 444 * <p> 445 * Blocks until a line terminating sequence has been read, the end of the 446 * file is reached or an exception is thrown. 447 * 448 * @return the contents of the line or {@code null} if no characters have 449 * been read before the end of the file has been reached. 450 * @throws IOException 451 * if this file is closed or another I/O error occurs. 452 */ 453 public final String readLine() throws IOException { 454 StringBuilder line = new StringBuilder(80); // Typical line length 455 boolean foundTerminator = false; 456 long unreadPosition = 0; 457 while (true) { 458 int nextByte = read(); 459 switch (nextByte) { 460 case -1: 461 return line.length() != 0 ? line.toString() : null; 462 case (byte) '\r': 463 if (foundTerminator) { 464 seek(unreadPosition); 465 return line.toString(); 466 } 467 foundTerminator = true; 468 /* Have to be able to peek ahead one byte */ 469 unreadPosition = getFilePointer(); 470 break; 471 case (byte) '\n': 472 return line.toString(); 473 default: 474 if (foundTerminator) { 475 seek(unreadPosition); 476 return line.toString(); 477 } 478 line.append((char) nextByte); 479 } 480 } 481 } 482 483 /** 484 * Reads a big-endian 64-bit long from the current position in this file. Blocks until 485 * eight bytes have been read, the end of the file is reached or an 486 * exception is thrown. 487 * 488 * @return the next long value from this file. 489 * @throws EOFException 490 * if the end of this file is detected. 491 * @throws IOException 492 * if this file is closed or another I/O error occurs. 493 * @see #writeLong(long) 494 */ 495 public final long readLong() throws IOException { 496 readFully(scratch, 0, SizeOf.LONG); 497 return Memory.peekLong(scratch, 0, ByteOrder.BIG_ENDIAN); 498 } 499 500 /** 501 * Reads a big-endian 16-bit short from the current position in this file. Blocks until 502 * two bytes have been read, the end of the file is reached or an exception 503 * is thrown. 504 * 505 * @return the next short value from this file. 506 * @throws EOFException 507 * if the end of this file is detected. 508 * @throws IOException 509 * if this file is closed or another I/O error occurs. 510 * @see #writeShort(int) 511 */ 512 public final short readShort() throws IOException { 513 readFully(scratch, 0, SizeOf.SHORT); 514 return Memory.peekShort(scratch, 0, ByteOrder.BIG_ENDIAN); 515 } 516 517 /** 518 * Reads an unsigned 8-bit byte from the current position in this file and 519 * returns it as an integer. Blocks until one byte has been read, the end of 520 * the file is reached or an exception is thrown. 521 * 522 * @return the next unsigned byte value from this file as an int. 523 * @throws EOFException 524 * if the end of this file is detected. 525 * @throws IOException 526 * if this file is closed or another I/O error occurs. 527 * @see #writeByte(int) 528 */ 529 public final int readUnsignedByte() throws IOException { 530 int temp = this.read(); 531 if (temp < 0) { 532 throw new EOFException(); 533 } 534 return temp; 535 } 536 537 /** 538 * Reads an unsigned big-endian 16-bit short from the current position in this file and 539 * returns it as an integer. Blocks until two bytes have been read, the end of 540 * the file is reached or an exception is thrown. 541 * 542 * @return the next unsigned short value from this file as an int. 543 * @throws EOFException 544 * if the end of this file is detected. 545 * @throws IOException 546 * if this file is closed or another I/O error occurs. 547 * @see #writeShort(int) 548 */ 549 public final int readUnsignedShort() throws IOException { 550 return ((int) readShort()) & 0xffff; 551 } 552 553 /** 554 * Reads a string that is encoded in {@link DataInput modified UTF-8} from 555 * this file. The number of bytes that must be read for the complete string 556 * is determined by the first two bytes read from the file. Blocks until all 557 * required bytes have been read, the end of the file is reached or an 558 * exception is thrown. 559 * 560 * @return the next string encoded in {@link DataInput modified UTF-8} from 561 * this file. 562 * @throws EOFException 563 * if the end of this file is detected. 564 * @throws IOException 565 * if this file is closed or another I/O error occurs. 566 * @throws UTFDataFormatException 567 * if the bytes read cannot be decoded into a character string. 568 * @see #writeUTF(String) 569 */ 570 public final String readUTF() throws IOException { 571 int utfSize = readUnsignedShort(); 572 if (utfSize == 0) { 573 return ""; 574 } 575 byte[] buf = new byte[utfSize]; 576 if (read(buf, 0, buf.length) != buf.length) { 577 throw new EOFException(); 578 } 579 return ModifiedUtf8.decode(buf, new char[utfSize], 0, utfSize); 580 } 581 582 /** 583 * Moves this file's file pointer to a new position, from where following 584 * {@code read}, {@code write} or {@code skip} operations are done. The 585 * position may be greater than the current length of the file, but the 586 * file's length will only change if the moving of the pointer is followed 587 * by a {@code write} operation. 588 * 589 * @param offset 590 * the new file pointer position. 591 * @throws IOException 592 * if this file is closed, {@code pos < 0} or another I/O error 593 * occurs. 594 */ 595 public void seek(long offset) throws IOException { 596 if (offset < 0) { 597 throw new IOException("offset < 0: " + offset); 598 } 599 try { 600 Libcore.os.lseek(fd, offset, SEEK_SET); 601 } catch (ErrnoException errnoException) { 602 throw errnoException.rethrowAsIOException(); 603 } 604 } 605 606 /** 607 * Sets the length of this file to {@code newLength}. If the current file is 608 * smaller, it is expanded but the contents from the previous end of the 609 * file to the new end are undefined. The file is truncated if its current 610 * size is bigger than {@code newLength}. If the current file pointer 611 * position is in the truncated part, it is set to the end of the file. 612 * 613 * @param newLength 614 * the new file length in bytes. 615 * @throws IllegalArgumentException 616 * if {@code newLength < 0}. 617 * @throws IOException 618 * if this file is closed or another I/O error occurs. 619 */ 620 public void setLength(long newLength) throws IOException { 621 if (newLength < 0) { 622 throw new IllegalArgumentException("newLength < 0"); 623 } 624 try { 625 Libcore.os.ftruncate(fd, newLength); 626 } catch (ErrnoException errnoException) { 627 throw errnoException.rethrowAsIOException(); 628 } 629 630 long filePointer = getFilePointer(); 631 if (filePointer > newLength) { 632 seek(newLength); 633 } 634 635 // if we are in "rws" mode, attempt to sync file+metadata 636 if (syncMetadata) { 637 fd.sync(); 638 } 639 } 640 641 /** 642 * Skips over {@code count} bytes in this file. Less than {@code count} 643 * bytes are skipped if the end of the file is reached or an exception is 644 * thrown during the operation. Nothing is done if {@code count} is 645 * negative. 646 * 647 * @param count 648 * the number of bytes to skip. 649 * @return the number of bytes actually skipped. 650 * @throws IOException 651 * if this file is closed or another I/O error occurs. 652 */ 653 public int skipBytes(int count) throws IOException { 654 if (count > 0) { 655 long currentPos = getFilePointer(), eof = length(); 656 int newCount = (int) ((currentPos + count > eof) ? eof - currentPos : count); 657 seek(currentPos + newCount); 658 return newCount; 659 } 660 return 0; 661 } 662 663 /** 664 * Writes the entire contents of the byte array {@code buffer} to this file, 665 * starting at the current file pointer. 666 * 667 * @param buffer 668 * the buffer to write. 669 * @throws IOException 670 * if an I/O error occurs while writing to this file. 671 */ 672 public void write(byte[] buffer) throws IOException { 673 write(buffer, 0, buffer.length); 674 } 675 676 /** 677 * Writes {@code byteCount} bytes from the byte array {@code buffer} to this 678 * file, starting at the current file pointer and using {@code byteOffset} as 679 * the first position within {@code buffer} to get bytes. 680 * 681 * @throws IndexOutOfBoundsException 682 * if {@code byteCount < 0}, {@code byteOffset < 0} or {@code byteCount + 683 * byteOffset} is greater than the size of {@code buffer}. 684 * @throws IOException 685 * if an I/O error occurs while writing to this file. 686 */ 687 public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException { 688 IoBridge.write(fd, buffer, byteOffset, byteCount); 689 // if we are in "rws" mode, attempt to sync file+metadata 690 if (syncMetadata) { 691 fd.sync(); 692 } 693 } 694 695 /** 696 * Writes a byte to this file, starting at the current file pointer. Only 697 * the least significant byte of the integer {@code oneByte} is written. 698 * 699 * @param oneByte 700 * the byte to write to this file. 701 * @throws IOException 702 * if this file is closed or another I/O error occurs. 703 * @see #read() 704 */ 705 public void write(int oneByte) throws IOException { 706 scratch[0] = (byte) (oneByte & 0xff); 707 write(scratch, 0, 1); 708 } 709 710 /** 711 * Writes a boolean to this file as a single byte (1 for true, 0 for false), starting at the 712 * current file pointer. 713 * 714 * @param val 715 * the boolean to write to this file. 716 * @throws IOException 717 * if this file is closed or another I/O error occurs. 718 * @see #readBoolean() 719 */ 720 public final void writeBoolean(boolean val) throws IOException { 721 write(val ? 1 : 0); 722 } 723 724 /** 725 * Writes an 8-bit byte to this file, starting at the current file pointer. 726 * Only the least significant byte of the integer {@code val} is written. 727 * 728 * @param val 729 * the byte to write to this file. 730 * @throws IOException 731 * if this file is closed or another I/O error occurs. 732 * @see #readByte() 733 * @see #readUnsignedByte() 734 */ 735 public final void writeByte(int val) throws IOException { 736 write(val & 0xFF); 737 } 738 739 /** 740 * Writes the low order 8-bit bytes from a string to this file, starting at 741 * the current file pointer. 742 * 743 * @param str 744 * the string containing the bytes to write to this file 745 * @throws IOException 746 * if an I/O error occurs while writing to this file. 747 */ 748 public final void writeBytes(String str) throws IOException { 749 byte[] bytes = new byte[str.length()]; 750 for (int index = 0; index < str.length(); index++) { 751 bytes[index] = (byte) (str.charAt(index) & 0xFF); 752 } 753 write(bytes); 754 } 755 756 /** 757 * Writes a big-endian 16-bit character to this file, starting at the current file 758 * pointer. Only the two least significant bytes of the integer {@code val} 759 * are written, with the high byte first. 760 * 761 * @param val 762 * the char to write to this file. 763 * @throws IOException 764 * if an I/O error occurs while writing to this file. 765 * @see #readChar() 766 */ 767 public final void writeChar(int val) throws IOException { 768 writeShort(val); 769 } 770 771 /** 772 * Writes big-endian 16-bit characters from {@code str} to this file, starting at the 773 * current file pointer. 774 * 775 * @param str 776 * the string to write to this file. 777 * @throws IOException 778 * if an I/O error occurs while writing to this file. 779 * @see #readChar() 780 */ 781 public final void writeChars(String str) throws IOException { 782 write(str.getBytes("UTF-16BE")); 783 } 784 785 /** 786 * Writes a big-endian 64-bit double to this file, starting at the current file 787 * pointer. The bytes are those returned by 788 * {@link Double#doubleToLongBits(double)}, meaning a canonical NaN is used. 789 * 790 * @param val 791 * the double to write to this file. 792 * @throws IOException 793 * if an I/O error occurs while writing to this file. 794 * @see #readDouble() 795 */ 796 public final void writeDouble(double val) throws IOException { 797 writeLong(Double.doubleToLongBits(val)); 798 } 799 800 /** 801 * Writes a big-endian 32-bit float to this file, starting at the current file pointer. 802 * The bytes are those returned by {@link Float#floatToIntBits(float)}, meaning a canonical NaN 803 * is used. 804 * 805 * @param val 806 * the float to write to this file. 807 * @throws IOException 808 * if an I/O error occurs while writing to this file. 809 * @see #readFloat() 810 */ 811 public final void writeFloat(float val) throws IOException { 812 writeInt(Float.floatToIntBits(val)); 813 } 814 815 /** 816 * Writes a big-endian 32-bit integer to this file, starting at the current file 817 * pointer. 818 * 819 * @param val 820 * the int to write to this file. 821 * @throws IOException 822 * if an I/O error occurs while writing to this file. 823 * @see #readInt() 824 */ 825 public final void writeInt(int val) throws IOException { 826 Memory.pokeInt(scratch, 0, val, ByteOrder.BIG_ENDIAN); 827 write(scratch, 0, SizeOf.INT); 828 } 829 830 /** 831 * Writes a big-endian 64-bit long to this file, starting at the current file 832 * pointer. 833 * 834 * @param val 835 * the long to write to this file. 836 * @throws IOException 837 * if an I/O error occurs while writing to this file. 838 * @see #readLong() 839 */ 840 public final void writeLong(long val) throws IOException { 841 Memory.pokeLong(scratch, 0, val, ByteOrder.BIG_ENDIAN); 842 write(scratch, 0, SizeOf.LONG); 843 } 844 845 /** 846 * Writes a big-endian 16-bit short to this file, starting at the current file 847 * pointer. Only the two least significant bytes of the integer {@code val} 848 * are written. 849 * 850 * @param val 851 * the short to write to this file. 852 * @throws IOException 853 * if an I/O error occurs while writing to this file. 854 * @see #readShort() 855 * @see DataInput#readUnsignedShort() 856 */ 857 public final void writeShort(int val) throws IOException { 858 Memory.pokeShort(scratch, 0, (short) val, ByteOrder.BIG_ENDIAN); 859 write(scratch, 0, SizeOf.SHORT); 860 } 861 862 /** 863 * Writes a string encoded with {@link DataInput modified UTF-8} to this 864 * file, starting at the current file pointer. 865 * 866 * @param str 867 * the string to write in {@link DataInput modified UTF-8} 868 * format. 869 * @throws IOException 870 * if an I/O error occurs while writing to this file. 871 * @throws UTFDataFormatException 872 * if the encoded string is longer than 65535 bytes. 873 * @see #readUTF() 874 */ 875 public final void writeUTF(String str) throws IOException { 876 write(ModifiedUtf8.encode(str)); 877 } 878} 879