0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package java.io;
0019:
0020: import java.nio.channels.FileChannel;
0021:
0022: import org.apache.harmony.luni.platform.IFileSystem;
0023: import org.apache.harmony.luni.platform.Platform;
0024: import org.apache.harmony.luni.util.Msg;
0025: import org.apache.harmony.luni.util.Util;
0026:
0027: import org.apache.harmony.nio.FileChannelFactory;
0028:
0029: /**
0030: * RandomAccessFile is a class which allows positioning of the next read
0031: * anywhere in the file. This is useful for reading specific locations of files
0032: * or following links within a file. Most input classes only support forward
0033: * skipping.
0034: */
0035: public class RandomAccessFile implements DataInput, DataOutput,
0036: Closeable {
0037: /**
0038: * The FileDescriptor representing this RandomAccessFile.
0039: */
0040: private FileDescriptor fd;
0041:
0042: private boolean syncMetadata = false;
0043:
0044: // The unique file channel associated with this FileInputStream (lazily
0045: // initialized).
0046: private FileChannel channel;
0047:
0048: private IFileSystem fileSystem = Platform.getFileSystem();
0049:
0050: private boolean isReadOnly;
0051:
0052: private static class RepositionLock {
0053: }
0054:
0055: private Object repositionLock = new RepositionLock();
0056:
0057: /**
0058: * Constructs a new RandomAccessFile on the File <code>file</code> and
0059: * opens it according to the access String in <code>mode</code>. The
0060: * access mode may be one of <code>"r"</code> for read access only, or
0061: * <code>"rw"</code> for read/write access.
0062: *
0063: * @param file
0064: * the File to open.
0065: * @param mode
0066: * "r" for read only, or "rw" for read/write.
0067: *
0068: * @throws FileNotFoundException
0069: * If the <code>mode</code> is incorrect or the File cannot be
0070: * opened in the requested <code>mode</code>.
0071: *
0072: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
0073: * @see java.lang.SecurityManager#checkWrite(FileDescriptor)
0074: */
0075: public RandomAccessFile(File file, String mode)
0076: throws FileNotFoundException {
0077: super ();
0078:
0079: int options = 0;
0080:
0081: fd = new FileDescriptor();
0082:
0083: if (mode.equals("r")) { //$NON-NLS-1$
0084: isReadOnly = true;
0085: fd.readOnly = true;
0086: options = IFileSystem.O_RDONLY;
0087: } else if (mode.equals("rw") || mode.equals("rws") || mode.equals("rwd")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0088: isReadOnly = false;
0089: options = IFileSystem.O_RDWR;
0090:
0091: if (mode.equals("rws")) { //$NON-NLS-1$
0092: // Sync file and metadata with every write
0093: syncMetadata = true;
0094: } else if (mode.equals("rwd")) { //$NON-NLS-1$
0095: // Sync file, but not necessarily metadata
0096: options = IFileSystem.O_RDWRSYNC;
0097: }
0098: } else {
0099: throw new IllegalArgumentException(Msg.getString("K0081")); //$NON-NLS-1$
0100: }
0101:
0102: SecurityManager security = System.getSecurityManager();
0103: if (security != null) {
0104: security.checkRead(file.getPath());
0105: if (!isReadOnly) {
0106: security.checkWrite(file.getPath());
0107: }
0108: }
0109:
0110: fd.descriptor = fileSystem.open(file.properPath(true), options);
0111: channel = FileChannelFactory.getFileChannel(this ,
0112: fd.descriptor, options);
0113:
0114: // if we are in "rws" mode, attempt to sync file+metadata
0115: if (syncMetadata) {
0116: try {
0117: fd.sync();
0118: } catch (IOException e) {
0119: // Ignored
0120: }
0121: }
0122: }
0123:
0124: /**
0125: * Constructs a new RandomAccessFile on the file named <code>fileName</code>
0126: * and opens it according to the access String in <code>mode</code>. The
0127: * file may be absolute or relative to the System property
0128: * <code>"user.dir"</code>. The access mode may be one of
0129: * <code>"r"</code> for read access only, or <code>"rw"</code> for
0130: * read/write access.
0131: *
0132: * @param fileName
0133: * the filename of the file to open.
0134: * @param mode
0135: * "r" for read only, or "rw" for read/write.
0136: *
0137: * @throws FileNotFoundException
0138: * If the <code>mode</code> is incorrect or the file cannot be
0139: * opened in the requested <code>mode</code>.
0140: *
0141: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
0142: * @see java.lang.SecurityManager#checkWrite(FileDescriptor)
0143: */
0144: public RandomAccessFile(String fileName, String mode)
0145: throws FileNotFoundException {
0146: this (new File(fileName), mode);
0147: }
0148:
0149: /**
0150: * Close this RandomAccessFile.
0151: *
0152: * @throws IOException
0153: * If an error occurs attempting to close this RandomAccessFile.
0154: */
0155: public void close() throws IOException {
0156: synchronized (channel) {
0157: if (channel.isOpen()) {
0158: channel.close();
0159: }
0160: }
0161: synchronized (this ) {
0162: if (fd != null && fd.descriptor >= 0) {
0163: fileSystem.close(fd.descriptor);
0164: fd.descriptor = -1;
0165: }
0166: }
0167: }
0168:
0169: /**
0170: * Answers the FileChannel equivalent to this stream.
0171: * <p>
0172: * The file channel is write-only and has an initial position within the
0173: * file that is the same as the current position of this FileOutputStream
0174: * within the file. All changes made to the underlying file descriptor state
0175: * via the channel are visible by the output stream and vice versa.
0176: * </p>
0177: *
0178: * @return the file channel representation for this FileOutputStream.
0179: */
0180: public final synchronized FileChannel getChannel() {
0181: return channel;
0182: }
0183:
0184: /**
0185: * Answers the FileDescriptor representing the operating system resource for
0186: * this RandomAccessFile.
0187: *
0188: * @return the FileDescriptor for this RandomAccessFile.
0189: *
0190: * @throws IOException
0191: * If an error occurs attempting to get the FileDescriptor of
0192: * this RandomAccessFile.
0193: */
0194: public final FileDescriptor getFD() throws IOException {
0195: return fd;
0196: }
0197:
0198: /**
0199: * Answers the current position within this RandomAccessFile. All reads and
0200: * writes take place at the current file pointer position.
0201: *
0202: * @return the current file pointer position.
0203: *
0204: * @throws IOException
0205: * If an error occurs attempting to get the file pointer
0206: * position of this RandomAccessFile.
0207: */
0208: public long getFilePointer() throws IOException {
0209: openCheck();
0210: return fileSystem.seek(fd.descriptor, 0L, IFileSystem.SEEK_CUR);
0211: }
0212:
0213: /**
0214: * Checks to see if the file is currently open. Returns silently if it is,
0215: * and throws an exception if it is not.
0216: *
0217: * @throws IOException
0218: * the receiver is closed.
0219: */
0220: private synchronized void openCheck() throws IOException {
0221: if (fd.descriptor < 0) {
0222: throw new IOException();
0223: }
0224: }
0225:
0226: /**
0227: * Answers the current length of this RandomAccessFile in bytes.
0228: *
0229: * @return the current file length in bytes.
0230: *
0231: * @throws IOException
0232: * If an error occurs attempting to get the file length of this
0233: * RandomAccessFile.
0234: */
0235: public long length() throws IOException {
0236: openCheck();
0237: synchronized (repositionLock) {
0238: long currentPosition = fileSystem.seek(fd.descriptor, 0L,
0239: IFileSystem.SEEK_CUR);
0240: long endOfFilePosition = fileSystem.seek(fd.descriptor, 0L,
0241: IFileSystem.SEEK_END);
0242: fileSystem.seek(fd.descriptor, currentPosition,
0243: IFileSystem.SEEK_SET);
0244: return endOfFilePosition;
0245: }
0246: }
0247:
0248: /**
0249: * Reads a single byte from this RandomAccessFile and returns the result as
0250: * an int. The low-order byte is returned or -1 of the end of file was
0251: * encountered.
0252: *
0253: * @return the byte read or -1 if end of file.
0254: *
0255: * @throws IOException
0256: * If an error occurs attempting to read from this
0257: * RandomAccessFile.
0258: *
0259: * @see #write(byte[])
0260: * @see #write(byte[], int, int)
0261: * @see #write(int)
0262: */
0263: public int read() throws IOException {
0264: openCheck();
0265: byte[] bytes = new byte[1];
0266: synchronized (repositionLock) {
0267: long readed = fileSystem.read(fd.descriptor, bytes, 0, 1);
0268: return readed == -1 ? -1 : bytes[0] & 0xff;
0269: }
0270: }
0271:
0272: /**
0273: * Reads bytes from this RandomAccessFile into the byte array
0274: * <code>buffer</code>. The number of bytes actually read is returned.
0275: *
0276: * @param buffer
0277: * the buffer to read bytes into
0278: * @return the number of bytes actually read or -1 if end of file.
0279: *
0280: * @throws IOException
0281: * If an error occurs attempting to read from this
0282: * RandomAccessFile.
0283: *
0284: * @see #write(byte[])
0285: * @see #write(byte[], int, int)
0286: * @see #write(int)
0287: */
0288: public int read(byte[] buffer) throws IOException {
0289: return read(buffer, 0, buffer.length);
0290: }
0291:
0292: /**
0293: * Reads at most <code>count</code> bytes from this RandomAccessFile and
0294: * stores them in byte array <code>buffer</code> starting at
0295: * <code>offset</code>. Answer the number of bytes actually read or -1 if
0296: * no bytes were read and end of file was encountered.
0297: *
0298: * @param buffer
0299: * the byte array in which to store the read bytes.
0300: * @param offset
0301: * the offset in <code>buffer</code> to store the read bytes.
0302: * @param count
0303: * the maximum number of bytes to store in <code>buffer</code>.
0304: * @return the number of bytes actually read or -1 if end of file.
0305: *
0306: * @throws IOException
0307: * If an error occurs attempting to read from this
0308: * RandomAccessFile.
0309: *
0310: * @see #write(byte[])
0311: * @see #write(byte[], int, int)
0312: * @see #write(int)
0313: */
0314: public int read(byte[] buffer, int offset, int count)
0315: throws IOException {
0316: // have to have four comparisions to not miss integer overflow cases
0317: if (count > buffer.length - offset || count < 0 || offset < 0) {
0318: throw new IndexOutOfBoundsException();
0319: }
0320: if (0 == count) {
0321: return 0;
0322: }
0323: openCheck();
0324: synchronized (repositionLock) {
0325: return (int) fileSystem.read(fd.descriptor, buffer, offset,
0326: count);
0327: }
0328: }
0329:
0330: /**
0331: * Reads a boolean from this stream.
0332: *
0333: * @return boolean the next boolean value from the source stream.
0334: *
0335: * @throws IOException
0336: * If a problem occurs reading from this DataInputStream.
0337: *
0338: * @see DataOutput#writeBoolean(boolean)
0339: */
0340: public final boolean readBoolean() throws IOException {
0341: int temp = this .read();
0342: if (temp < 0) {
0343: throw new EOFException();
0344: }
0345: return temp != 0;
0346: }
0347:
0348: /**
0349: * Reads an 8-bit byte value from this stream.
0350: *
0351: * @return byte the next byte value from the source stream.
0352: *
0353: * @throws IOException
0354: * If a problem occurs reading from this DataInputStream.
0355: *
0356: * @see DataOutput#writeByte(int)
0357: */
0358: public final byte readByte() throws IOException {
0359: int temp = this .read();
0360: if (temp < 0) {
0361: throw new EOFException();
0362: }
0363: return (byte) temp;
0364: }
0365:
0366: /**
0367: * Reads a 16-bit character value from this stream.
0368: *
0369: * @return char the next <code>char</code> value from the source stream.
0370: *
0371: * @throws IOException
0372: * If a problem occurs reading from this DataInputStream.
0373: *
0374: * @see DataOutput#writeChar(int)
0375: */
0376: public final char readChar() throws IOException {
0377: byte[] buffer = new byte[2];
0378: if (read(buffer, 0, buffer.length) != buffer.length) {
0379: throw new EOFException();
0380: }
0381: return (char) (((buffer[0] & 0xff) << 8) + (buffer[1] & 0xff));
0382: }
0383:
0384: /**
0385: * Reads a 64-bit <code>double</code> value from this stream.
0386: *
0387: * @return double the next <code>double</code> value from the source
0388: * stream.
0389: *
0390: * @throws IOException
0391: * If a problem occurs reading from this DataInputStream.
0392: *
0393: * @see DataOutput#writeDouble(double)
0394: */
0395: public final double readDouble() throws IOException {
0396: return Double.longBitsToDouble(readLong());
0397: }
0398:
0399: /**
0400: * Reads a 32-bit <code>float</code> value from this stream.
0401: *
0402: * @return float the next <code>float</code> value from the source stream.
0403: *
0404: * @throws IOException
0405: * If a problem occurs reading from this DataInputStream.
0406: *
0407: * @see DataOutput#writeFloat(float)
0408: */
0409: public final float readFloat() throws IOException {
0410: return Float.intBitsToFloat(readInt());
0411: }
0412:
0413: /**
0414: * Reads bytes from this stream into the byte array <code>buffer</code>.
0415: * This method will block until <code>buffer.length</code> number of bytes
0416: * have been read.
0417: *
0418: * @param buffer
0419: * the buffer to read bytes into
0420: *
0421: * @throws IOException
0422: * If a problem occurs reading from this DataInputStream.
0423: *
0424: * @see DataOutput#write(byte[])
0425: * @see DataOutput#write(byte[], int, int)
0426: */
0427: public final void readFully(byte[] buffer) throws IOException {
0428: readFully(buffer, 0, buffer.length);
0429: }
0430:
0431: /**
0432: * Read bytes from this stream and stores them in byte array
0433: * <code>buffer</code> starting at offset <code>offset</code>. This
0434: * method blocks until <code>count</code> number of bytes have been read.
0435: *
0436: * @param buffer
0437: * the byte array in which to store the read bytes.
0438: * @param offset
0439: * the offset in <code>buffer</code> to store the read bytes.
0440: * @param count
0441: * the maximum number of bytes to store in <code>buffer</code>.
0442: *
0443: * @throws IOException
0444: * If a problem occurs reading from this DataInputStream.
0445: *
0446: * @see DataOutput#write(byte[])
0447: * @see DataOutput#write(byte[], int, int)
0448: */
0449: public final void readFully(byte[] buffer, int offset, int count)
0450: throws IOException {
0451: if (buffer == null) {
0452: throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$
0453: }
0454: // avoid int overflow
0455: if (offset < 0 || offset > buffer.length || count < 0
0456: || count > buffer.length - offset) {
0457: throw new IndexOutOfBoundsException();
0458: }
0459: while (count > 0) {
0460: int result = read(buffer, offset, count);
0461: if (result < 0) {
0462: throw new EOFException();
0463: }
0464: offset += result;
0465: count -= result;
0466: }
0467: }
0468:
0469: /**
0470: * Reads a 32-bit integer value from this stream.
0471: *
0472: * @return int the next <code>int</code> value from the source stream.
0473: *
0474: * @throws IOException
0475: * If a problem occurs reading from this DataInputStream.
0476: *
0477: * @see DataOutput#writeInt(int)
0478: */
0479: public final int readInt() throws IOException {
0480: byte[] buffer = new byte[4];
0481: if (read(buffer, 0, buffer.length) != buffer.length) {
0482: throw new EOFException();
0483: }
0484: return ((buffer[0] & 0xff) << 24) + ((buffer[1] & 0xff) << 16)
0485: + ((buffer[2] & 0xff) << 8) + (buffer[3] & 0xff);
0486: }
0487:
0488: /**
0489: * Answers a <code>String</code> representing the next line of text
0490: * available in this BufferedReader. A line is represented by 0 or more
0491: * characters followed by <code>'\n'</code>, <code>'\r'</code>,
0492: * <code>"\n\r"</code> or end of stream. The <code>String</code> does
0493: * not include the newline sequence.
0494: *
0495: * @return String the contents of the line or null if no characters were
0496: * read before end of stream.
0497: *
0498: * @throws IOException
0499: * If the BufferedReader is already closed or some other IO
0500: * error occurs.
0501: */
0502: public final String readLine() throws IOException {
0503: StringBuilder line = new StringBuilder(80); // Typical line length
0504: boolean foundTerminator = false;
0505: long unreadPosition = 0;
0506: while (true) {
0507: int nextByte = read();
0508: switch (nextByte) {
0509: case -1:
0510: return line.length() != 0 ? line.toString() : null;
0511: case (byte) '\r':
0512: if (foundTerminator) {
0513: seek(unreadPosition);
0514: return line.toString();
0515: }
0516: foundTerminator = true;
0517: /* Have to be able to peek ahead one byte */
0518: unreadPosition = getFilePointer();
0519: break;
0520: case (byte) '\n':
0521: return line.toString();
0522: default:
0523: if (foundTerminator) {
0524: seek(unreadPosition);
0525: return line.toString();
0526: }
0527: line.append((char) nextByte);
0528: }
0529: }
0530: }
0531:
0532: /**
0533: * Reads a 64-bit <code>long</code> value from this stream.
0534: *
0535: * @return long the next <code>long</code> value from the source stream.
0536: *
0537: * @throws IOException
0538: * If a problem occurs reading from this DataInputStream.
0539: *
0540: * @see DataOutput#writeLong(long)
0541: */
0542: public final long readLong() throws IOException {
0543: byte[] buffer = new byte[8];
0544: if (read(buffer, 0, buffer.length) != buffer.length) {
0545: throw new EOFException();
0546: }
0547: return ((long) (((buffer[0] & 0xff) << 24)
0548: + ((buffer[1] & 0xff) << 16)
0549: + ((buffer[2] & 0xff) << 8) + (buffer[3] & 0xff)) << 32)
0550: + ((long) (buffer[4] & 0xff) << 24)
0551: + ((buffer[5] & 0xff) << 16)
0552: + ((buffer[6] & 0xff) << 8) + (buffer[7] & 0xff);
0553: }
0554:
0555: /**
0556: * Reads a 16-bit <code>short</code> value from this stream.
0557: *
0558: * @return short the next <code>short</code> value from the source stream.
0559: *
0560: * @throws IOException
0561: * If a problem occurs reading from this DataInputStream.
0562: *
0563: * @see DataOutput#writeShort(int)
0564: */
0565: public final short readShort() throws IOException {
0566: byte[] buffer = new byte[2];
0567: if (read(buffer, 0, buffer.length) != buffer.length) {
0568: throw new EOFException();
0569: }
0570: return (short) (((buffer[0] & 0xff) << 8) + (buffer[1] & 0xff));
0571: }
0572:
0573: /**
0574: * Reads an unsigned 8-bit <code>byte</code> value from this stream and
0575: * returns it as an int.
0576: *
0577: * @return int the next unsigned byte value from the source stream.
0578: *
0579: * @throws IOException
0580: * If a problem occurs reading from this DataInputStream.
0581: *
0582: * @see DataOutput#writeByte(int)
0583: */
0584: public final int readUnsignedByte() throws IOException {
0585: int temp = this .read();
0586: if (temp < 0) {
0587: throw new EOFException();
0588: }
0589: return temp;
0590: }
0591:
0592: /**
0593: * Reads a 16-bit unsigned <code>short</code> value from this stream and
0594: * returns it as an int.
0595: *
0596: * @return int the next unsigned <code>short</code> value from the source
0597: * stream.
0598: *
0599: * @throws IOException
0600: * If a problem occurs reading from this DataInputStream.
0601: *
0602: * @see DataOutput#writeShort(int)
0603: */
0604: public final int readUnsignedShort() throws IOException {
0605: byte[] buffer = new byte[2];
0606: if (read(buffer, 0, buffer.length) != buffer.length) {
0607: throw new EOFException();
0608: }
0609: return ((buffer[0] & 0xff) << 8) + (buffer[1] & 0xff);
0610: }
0611:
0612: /**
0613: * Reads a UTF format String from this Stream.
0614: *
0615: * @return String the next UTF String from the source stream.
0616: *
0617: * @throws IOException
0618: * If a problem occurs reading from this DataInputStream.
0619: *
0620: * @see DataOutput#writeUTF(java.lang.String)
0621: */
0622: public final String readUTF() throws IOException {
0623: int utfSize = readUnsignedShort();
0624: if (utfSize == 0) {
0625: return ""; //$NON-NLS-1$
0626: }
0627: byte[] buf = new byte[utfSize];
0628: if (read(buf, 0, buf.length) != buf.length) {
0629: throw new EOFException();
0630: }
0631: return Util.convertFromUTF8(buf, 0, utfSize);
0632: }
0633:
0634: /**
0635: * Seeks to the position <code>pos</code> in this RandomAccessFile. All
0636: * read/write/skip methods sent will be relative to <code>pos</code>.
0637: *
0638: * @param pos
0639: * the desired file pointer position
0640: *
0641: * @throws IOException
0642: * If the stream is already closed or another IOException
0643: * occurs.
0644: */
0645: public void seek(long pos) throws IOException {
0646: if (pos < 0) {
0647: // seek position is negative
0648: throw new IOException(Msg.getString("K0347")); //$NON-NLS-1$
0649: }
0650: openCheck();
0651: synchronized (repositionLock) {
0652: fileSystem.seek(fd.descriptor, pos, IFileSystem.SEEK_SET);
0653: }
0654: }
0655:
0656: /**
0657: * Set the length of this file to be <code>newLength</code>. If the
0658: * current file is smaller, it will be expanded and the filePosition will be
0659: * set to the new file length. If the <code>newLength</code> is smaller
0660: * then the file will be truncated.
0661: *
0662: * @param newLength
0663: * the desired file length
0664: *
0665: * @throws IOException
0666: * If the stream is already closed or another IOException
0667: * occurs.
0668: */
0669: public void setLength(long newLength) throws IOException {
0670: openCheck();
0671: if (newLength < 0) {
0672: throw new IllegalArgumentException();
0673: }
0674: synchronized (repositionLock) {
0675: long position = fileSystem.seek(fd.descriptor, 0,
0676: IFileSystem.SEEK_CUR);
0677: fileSystem.truncate(fd.descriptor, newLength);
0678: seek(position > newLength ? newLength : position);
0679: }
0680:
0681: // if we are in "rws" mode, attempt to sync file+metadata
0682: if (syncMetadata) {
0683: fd.sync();
0684: }
0685: }
0686:
0687: /**
0688: * Skips <code>count</code> number of bytes in this stream. Subsequent
0689: * <code>read()</code>'s will not return these bytes unless
0690: * <code>reset()</code> is used.
0691: *
0692: * @param count
0693: * the number of bytes to skip.
0694: * @return the number of bytes actually skipped.
0695: *
0696: * @throws IOException
0697: * If the stream is already closed or another IOException
0698: * occurs.
0699: */
0700: public int skipBytes(int count) throws IOException {
0701: if (count > 0) {
0702: long currentPos = getFilePointer(), eof = length();
0703: int newCount = (int) ((currentPos + count > eof) ? eof
0704: - currentPos : count);
0705: seek(currentPos + newCount);
0706: return newCount;
0707: }
0708: return 0;
0709: }
0710:
0711: /**
0712: * Writes the entire contents of the byte array <code>buffer</code> to
0713: * this RandomAccessFile starting at the current file pointer.
0714: *
0715: * @param buffer
0716: * the buffer to be written.
0717: *
0718: * @throws IOException
0719: * If an error occurs trying to write to this RandomAccessFile.
0720: *
0721: * @see #read()
0722: * @see #read(byte[])
0723: * @see #read(byte[], int, int)
0724: */
0725: public void write(byte[] buffer) throws IOException {
0726: write(buffer, 0, buffer.length);
0727: }
0728:
0729: /**
0730: * Writes <code>count</code> bytes from the byte array <code>buffer</code>
0731: * starting at <code>offset</code> to this RandomAccessFile starting at
0732: * the current file pointer..
0733: *
0734: * @param buffer
0735: * the bytes to be written
0736: * @param offset
0737: * offset in buffer to get bytes
0738: * @param count
0739: * number of bytes in buffer to write
0740: *
0741: * @throws IOException
0742: * If an error occurs attempting to write to this
0743: * RandomAccessFile.
0744: * @throws IndexOutOfBoundsException
0745: * If offset or count are outside of bounds.
0746: *
0747: * @see #read()
0748: * @see #read(byte[])
0749: * @see #read(byte[], int, int)
0750: */
0751: public void write(byte[] buffer, int offset, int count)
0752: throws IOException {
0753: if (count > buffer.length - offset || count < 0 || offset < 0) {
0754: throw new IndexOutOfBoundsException();
0755: }
0756: if (count == 0) {
0757: return;
0758: }
0759: synchronized (repositionLock) {
0760: fileSystem.write(fd.descriptor, buffer, offset, count);
0761: }
0762:
0763: // if we are in "rws" mode, attempt to sync file+metadata
0764: if (syncMetadata) {
0765: fd.sync();
0766: }
0767: }
0768:
0769: /**
0770: * Writes the specified byte <code>oneByte</code> to this RandomAccessFile
0771: * starting at the current file pointer. Only the low order byte of
0772: * <code>oneByte</code> is written.
0773: *
0774: * @param oneByte
0775: * the byte to be written
0776: *
0777: * @throws IOException
0778: * If an error occurs attempting to write to this
0779: * RandomAccessFile.
0780: *
0781: * @see #read()
0782: * @see #read(byte[])
0783: * @see #read(byte[], int, int)
0784: */
0785: public void write(int oneByte) throws IOException {
0786: openCheck();
0787: byte[] bytes = new byte[1];
0788: bytes[0] = (byte) (oneByte & 0xff);
0789: synchronized (repositionLock) {
0790: fileSystem.write(fd.descriptor, bytes, 0, 1);
0791: }
0792:
0793: // if we are in "rws" mode, attempt to sync file+metadata
0794: if (syncMetadata) {
0795: fd.sync();
0796: }
0797: }
0798:
0799: /**
0800: * Writes a boolean to this output stream.
0801: *
0802: * @param val
0803: * the boolean value to write to the OutputStream
0804: *
0805: * @throws IOException
0806: * If an error occurs attempting to write to this
0807: * DataOutputStream.
0808: *
0809: * @see DataInput#readBoolean()
0810: */
0811: public final void writeBoolean(boolean val) throws IOException {
0812: write(val ? 1 : 0);
0813: }
0814:
0815: /**
0816: * Writes a 8-bit byte to this output stream.
0817: *
0818: * @param val
0819: * the byte value to write to the OutputStream
0820: *
0821: * @throws java.io.IOException
0822: * If an error occurs attempting to write to this
0823: * DataOutputStream.
0824: *
0825: * @see #readByte()
0826: * @see #readUnsignedByte()
0827: */
0828: public final void writeByte(int val) throws IOException {
0829: write(val & 0xFF);
0830: }
0831:
0832: /**
0833: * Writes the low order 8-bit bytes from a String to this output stream.
0834: *
0835: * @param str
0836: * the String containing the bytes to write to the OutputStream
0837: *
0838: * @throws IOException
0839: * If an error occurs attempting to write to this
0840: * DataOutputStream.
0841: *
0842: * @see #read(byte[])
0843: * @see #read(byte[],int,int)
0844: * @see #readFully(byte[])
0845: * @see #readFully(byte[],int,int)
0846: */
0847: public final void writeBytes(String str) throws IOException {
0848: byte bytes[] = new byte[str.length()];
0849: for (int index = 0; index < str.length(); index++) {
0850: bytes[index] = (byte) (str.charAt(index) & 0xFF);
0851: }
0852: write(bytes);
0853: }
0854:
0855: /**
0856: * Writes the specified 16-bit character to the OutputStream. Only the lower
0857: * 2 bytes are written with the higher of the 2 bytes written first. This
0858: * represents the Unicode value of val.
0859: *
0860: * @param val
0861: * the character to be written
0862: *
0863: * @throws IOException
0864: * If an error occurs attempting to write to this
0865: * DataOutputStream.
0866: *
0867: * @see DataInput#readChar()
0868: */
0869: public final void writeChar(int val) throws IOException {
0870: byte[] buffer = new byte[2];
0871: buffer[0] = (byte) (val >> 8);
0872: buffer[1] = (byte) val;
0873: write(buffer, 0, buffer.length);
0874: }
0875:
0876: /**
0877: * Writes the specified 16-bit characters contained in str to the
0878: * OutputStream. Only the lower 2 bytes of each character are written with
0879: * the higher of the 2 bytes written first. This represents the Unicode
0880: * value of each character in str.
0881: *
0882: * @param str
0883: * the String whose characters are to be written.
0884: *
0885: * @throws IOException
0886: * If an error occurs attempting to write to this
0887: * DataOutputStream.
0888: *
0889: * @see DataInput#readChar()
0890: */
0891: public final void writeChars(String str) throws IOException {
0892: byte newBytes[] = new byte[str.length() * 2];
0893: for (int index = 0; index < str.length(); index++) {
0894: int newIndex = index == 0 ? index : index * 2;
0895: newBytes[newIndex] = (byte) ((str.charAt(index) >> 8) & 0xFF);
0896: newBytes[newIndex + 1] = (byte) (str.charAt(index) & 0xFF);
0897: }
0898: write(newBytes);
0899: }
0900:
0901: /**
0902: * Writes a 64-bit double to this output stream. The resulting output is the
0903: * 8 bytes resulting from calling Double.doubleToLongBits().
0904: *
0905: * @param val
0906: * the double to be written.
0907: *
0908: * @throws IOException
0909: * If an error occurs attempting to write to this
0910: * DataOutputStream.
0911: *
0912: * @see DataInput#readDouble()
0913: */
0914: public final void writeDouble(double val) throws IOException {
0915: writeLong(Double.doubleToLongBits(val));
0916: }
0917:
0918: /**
0919: * Writes a 32-bit float to this output stream. The resulting output is the
0920: * 4 bytes resulting from calling Float.floatToIntBits().
0921: *
0922: * @param val
0923: * the float to be written.
0924: *
0925: * @throws IOException
0926: * If an error occurs attempting to write to this
0927: * DataOutputStream.
0928: *
0929: * @see DataInput#readFloat()
0930: */
0931: public final void writeFloat(float val) throws IOException {
0932: writeInt(Float.floatToIntBits(val));
0933: }
0934:
0935: /**
0936: * Writes a 32-bit int to this output stream. The resulting output is the 4
0937: * bytes, highest order first, of val.
0938: *
0939: * @param val
0940: * the int to be written.
0941: *
0942: * @throws IOException
0943: * If an error occurs attempting to write to this
0944: * DataOutputStream.
0945: *
0946: * @see DataInput#readInt()
0947: */
0948: public final void writeInt(int val) throws IOException {
0949: byte[] buffer = new byte[4];
0950: buffer[0] = (byte) (val >> 24);
0951: buffer[1] = (byte) (val >> 16);
0952: buffer[2] = (byte) (val >> 8);
0953: buffer[3] = (byte) val;
0954: write(buffer, 0, buffer.length);
0955: }
0956:
0957: /**
0958: * Writes a 64-bit long to this output stream. The resulting output is the 8
0959: * bytes, highest order first, of val.
0960: *
0961: * @param val
0962: * the long to be written.
0963: *
0964: * @throws IOException
0965: * If an error occurs attempting to write to this
0966: * DataOutputStream.
0967: *
0968: * @see DataInput#readLong()
0969: */
0970: public final void writeLong(long val) throws IOException {
0971: byte[] buffer = new byte[8];
0972: int t = (int) (val >> 32);
0973: buffer[0] = (byte) (t >> 24);
0974: buffer[1] = (byte) (t >> 16);
0975: buffer[2] = (byte) (t >> 8);
0976: buffer[3] = (byte) t;
0977: buffer[4] = (byte) (val >> 24);
0978: buffer[5] = (byte) (val >> 16);
0979: buffer[6] = (byte) (val >> 8);
0980: buffer[7] = (byte) val;
0981: write(buffer, 0, buffer.length);
0982: }
0983:
0984: /**
0985: * Writes the specified 16-bit short to the OutputStream. Only the lower 2
0986: * bytes are written with the higher of the 2 bytes written first.
0987: *
0988: * @param val
0989: * the short to be written
0990: *
0991: * @throws IOException
0992: * If an error occurs attempting to write to this
0993: * DataOutputStream.
0994: *
0995: * @see DataInput#readShort()
0996: * @see DataInput#readUnsignedShort()
0997: */
0998: public final void writeShort(int val) throws IOException {
0999: writeChar(val);
1000: }
1001:
1002: /**
1003: * Writes the specified String out in UTF format.
1004: *
1005: * @param str
1006: * the String to be written in UTF format.
1007: *
1008: * @throws IOException
1009: * If an error occurs attempting to write to this
1010: * DataOutputStream.
1011: *
1012: * @see DataInput#readUTF()
1013: */
1014: public final void writeUTF(String str) throws IOException {
1015: int utfCount = 0, length = str.length();
1016: for (int i = 0; i < length; i++) {
1017: int charValue = str.charAt(i);
1018: if (charValue > 0 && charValue <= 127) {
1019: utfCount++;
1020: } else if (charValue <= 2047) {
1021: utfCount += 2;
1022: } else {
1023: utfCount += 3;
1024: }
1025: }
1026: if (utfCount > 65535) {
1027: throw new UTFDataFormatException(Msg.getString("K0068")); //$NON-NLS-1$
1028: }
1029: byte utfBytes[] = new byte[utfCount + 2];
1030: int utfIndex = 2;
1031: for (int i = 0; i < length; i++) {
1032: int charValue = str.charAt(i);
1033: if (charValue > 0 && charValue <= 127) {
1034: utfBytes[utfIndex++] = (byte) charValue;
1035: } else if (charValue <= 2047) {
1036: utfBytes[utfIndex++] = (byte) (0xc0 | (0x1f & (charValue >> 6)));
1037: utfBytes[utfIndex++] = (byte) (0x80 | (0x3f & charValue));
1038: } else {
1039: utfBytes[utfIndex++] = (byte) (0xe0 | (0x0f & (charValue >> 12)));
1040: utfBytes[utfIndex++] = (byte) (0x80 | (0x3f & (charValue >> 6)));
1041: utfBytes[utfIndex++] = (byte) (0x80 | (0x3f & charValue));
1042: }
1043: }
1044: utfBytes[0] = (byte) (utfCount >> 8);
1045: utfBytes[1] = (byte) utfCount;
1046: write(utfBytes);
1047: }
1048: }
|