All Downloads are FREE. Search and download functionalities are using the official Maven repository.

umcg.genetica.io.bin.RandomAccessFile Maven / Gradle / Ivy

There is a newer version: 1.0.7
Show newest version
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package umcg.genetica.io.bin;

/*
 * Copyright 1997, University Corporation for Atmospheric Research
 * See COPYRIGHT file for copying and redistribution conditions.
 *
 * RandomAccessFile.java.  By Russ Rew, based on
 * BufferedRandomAccessFile by Alex McManus, based on Sun's source code
 * for java.io.RandomAccessFile.  For Alex McManus version from which
 * this derives, see his 
 * Freeware Java Classes.  
 */
//DJ package ucar.netcdf;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.EOFException;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UTFDataFormatException;
import java.util.Date;
import java.util.Random;

/**
 * A buffered drop-in replacement for java.io.RandomAccessFile. Instances of
 * this class realise substantial speed increases over java.io.RandomAccessFile
 * through the use of buffering. This is a subclass of Object, as it was not
 * possible to subclass java.io.RandomAccessFile because many of the methods are
 * final. However, if it is necessary to use RandomAccessFile and
 * java.io.RandomAccessFile interchangeably, both classes implement the
 * DataInput and DataOutput interfaces.
 *
 * @author Alex McManus
 * @author Russ Rew
 * @version $Id: RandomAccessFile.java,v 1.2 1998/10/20 18:38:03 russ Exp $
 * @see DataInput
 * @see DataOutput
 * @see java.io.RandomAccessFile
 */
public class RandomAccessFile extends Object
        implements DataInput, DataOutput {

    /**
     * Read from the file. This is always implied.
     */
    public static final int READ = 1;
    /**
     * Write to the file.
     */
    public static final int WRITE = 2;
    /**
     * Create the file rather than overwriting it. This is ignored if mode is
     * not also WRITE.
     */
    public static final int CREATE = 4;
    /**
     * The default buffer size, in bytes.
     */
    protected static final int defaultBufferSize = 4096;
    /**
     * The underlying java.io.RandomAccessFile.
     */
    protected java.io.RandomAccessFile file;
    /**
     * The offset in bytes from the file start, of the next read or write
     * operation.
     */
    protected long filePosition;
    /**
     * The buffer used to load the data.
     */
    protected byte buffer[];
    /**
     * The offset in bytes of the start of the buffer, from the start of the
     * file.
     */
    protected long bufferStart;
    /**
     * The offset in bytes of the end of the data in the buffer, from the start
     * of the file. This can be calculated from
     * bufferStart + dataSize, but it is cached to speed up the
     * read( ) method.
     */
    protected long dataEnd;
    /**
     * The size of the data stored in the buffer, in bytes. This may be less
     * than the size of the buffer.
     */
    protected int dataSize;
    /**
     * True if we are at the end of the file.
     */
    protected boolean endOfFile;
    /**
     * The access mode of the file. This is a logical OR of READ, WRITE and
     * CREATE.
     */
    protected int mode;
    /**
     * True if the data in the buffer has been modified.
     */
    boolean bufferModified = false;

    /**
     * Create a new buffered random-access file with a default buffer size. Note
     * that the mode CREATE implies WRITE.
     *
     * @param filename the name of the file.
     * @param mode how the file is to be opened. This may be a combination
     * (logical OR) of CREATE, WRITE, and READ.
     * @exception IOException if an I/O error occurrs.
     * @exception SecurityException if a security manager exists, its checkRead
     * method is called with the name argument to see if the application is
     * allowed read access to the file. If the mode argument is WRITE, its
     * checkWrite method also is called with the name argument to see if the
     * application is allowed write access to the file. Either of these may
     * result in a security exception.
     */
    public RandomAccessFile(String filename, int mode)
            throws IOException {
        this(filename, mode, defaultBufferSize);
    }

    /**
     * Creates a random access file stream to read from, and optionally to write
     * to, a file with the specified name. 

The mode argument must either be * equal to * "r" or * "rw", indicating that the file is to be opened for input * only or for both input and output, respectively. If the mode is * "rw" and the file does not exist, then an attempt is made to * create it. * * @param name the system-dependent filename. * @param mode the access mode. * @exception IllegalArgumentException if the mode argument is not equal to "r" or to "rw". * @exception IOException if an I/O error occurs. * @exception SecurityException if a security manager exists, its * checkRead method is called with the name argument to see if * the application is allowed read access to the file. If the mode argument * is equal to "rw", its checkWrite method also is * called with the name argument to see if the application is allowed write * access to the file. Either of these may result in a security exception. * @see java.lang.SecurityException * @see java.lang.SecurityManager#checkRead(java.lang.String) */ public RandomAccessFile(String filename, String modeString) throws IOException { this(filename, modeString.equals("r") ? READ : (modeString.equals("rw") ? WRITE | READ : 0), defaultBufferSize); } /** * Creates a random access file stream to read from, and optionally to write * to, the file specified by the * File argument. A new {@link FileDescriptor} object is * created to represent this file connection.

The mode argument must * either be equal to * "r" or * "rw", indicating that the file is to be opened for input * only or for both input and output, respectively. The write methods on * this object will always throw an * IOException if the file is opened with a mode of * "r". If the mode is * "rw" and the file does not exist, then an attempt is made to * create it. * * @param file the file object. * @param mode the access mode. * @exception IllegalArgumentException if the mode argument is not equal to "r" or to "rw". * @exception IOException if an I/O error occurs. * @exception SecurityException if a security manager exists, its * checkRead method is called with the pathname of * the File argument to see if the application is allowed read * access to the file. If the mode argument is equal to "rw", * its checkWrite method also is called with the pathname to * see if the application is allowed write access to the file. * @see java.io.File#getPath() * @see java.lang.SecurityManager#checkRead(java.lang.String) */ public RandomAccessFile(File file, String modeString) throws IOException { this(file.getPath(), modeString); } /** * Create a new buffered random-access file with a specified buffer size. * Note that the mode CREATE implies WRITE, and the READ is always implied. * * @param filename the name of the file. * @param mode how the file is to be opened. This may be a combination * (logical OR) of CREATE, WRITE, and READ. * @param bufferSize the size of the temporary buffer, in bytes. * @exception IOException if an I/O error occurrs. * @exception SecurityException if a security manager exists, its checkRead * method is called with the name argument to see if the application is * allowed read access to the file. If the mode argument is WRITE, its * checkWrite method also is called with the name argument to see if the * application is allowed write access to the file. Either of these may * result in a security exception. */ public RandomAccessFile(File file, String modeString, int bufferSize) throws IOException { this(file.getPath(), modeString.equals("r") ? READ : (modeString.equals("rw") ? WRITE | READ : 0),bufferSize); } /** * Create a new buffered random-access file with a specified buffer size. * Note that the mode CREATE implies WRITE, and the READ is always implied. * * @param filename the name of the file. * @param mode how the file is to be opened. This may be a combination * (logical OR) of CREATE, WRITE, and READ. * @param bufferSize the size of the temporary buffer, in bytes. * @exception IOException if an I/O error occurrs. * @exception SecurityException if a security manager exists, its checkRead * method is called with the name argument to see if the application is * allowed read access to the file. If the mode argument is WRITE, its * checkWrite method also is called with the name argument to see if the * application is allowed write access to the file. Either of these may * result in a security exception. */ public RandomAccessFile(String filename, int mode, int bufferSize) throws IOException { this.mode = mode; // If we are CREATEing a file, we must also WRITE. READ is always // set. mode |= READ; if ((this.mode & CREATE) > 0) { this.mode |= WRITE; } // To match java.io.RandomAccessFile semantics, if we want to write // a nonexistant file, create it first (even if CREATE not set) File checkfile = new File(filename); if ((this.mode & WRITE) > 0 && !checkfile.exists()) { mode |= CREATE; } // If a new file is to be created, delete any existing file with the same name. if ((this.mode & CREATE) > 0) { if (checkfile.exists()) { if (!checkfile.delete()) { throw new IOException("Failed to delete " + filename); } } } // If only reading, check that the file exists. if (this.mode == READ && !(new File(filename)).exists()) { throw new FileNotFoundException(filename); } // Create the underlying file object. String modeString = ((this.mode & WRITE) > 0) ? "rw" : "r"; file = new java.io.RandomAccessFile(filename, modeString); // Initialise the buffer; bufferStart = 0; dataEnd = 0; dataSize = 0; filePosition = 0; buffer = new byte[bufferSize]; endOfFile = false; } /** * Close the file, and release any associated system resources. * * @exception IOException if an I/O error occurrs. */ public void close() throws IOException { // If we are writing and the buffer has been modified, flush the contents // of the buffer. if ((mode | WRITE) > 0 && bufferModified) { file.seek(bufferStart); file.write(buffer, 0, (int) dataSize); } // Close the underlying file object. file.close(); } /** * Set the position in the file for the next read or write. * * @param pos the offset (in bytes) from the start of the file. * @exception IOException if an I/O error occurrs. */ public final void seek(long pos) throws IOException { // If the seek is into the buffer, just update the file pointer. if (pos >= bufferStart && pos < dataEnd) { filePosition = pos; return; } // If the current buffer is modified, write it to disk. if (bufferModified) { flush(); } // Move to the position on the disk. file.seek(pos); filePosition = file.getFilePointer(); bufferStart = filePosition; // Fill the buffer from the disk. dataSize = file.read(buffer); if (dataSize < 0) { dataSize = 0; endOfFile = true; } else { endOfFile = false; } // Cache the position of the buffer end. dataEnd = bufferStart + dataSize; } /** * Returns the current position in the file, where the next read or write * will occur. * * @return the offset from the start of the file in bytes. * @exception IOException if an I/O error occurrs. */ public final long getFilePointer() throws IOException { return filePosition; } /** * Get the length of the file. The data in the buffer (which may not have * been written the disk yet) is taken into account. * * @return the length of the file in bytes. * @exception IOException if an I/O error occurrs. */ public long length() throws IOException { long fileLength = file.length(); if (fileLength < dataEnd) { return dataEnd; } else { return fileLength; } } /** * Returns the opaque file descriptor object associated with this file. * * @return the file descriptor object associated with this file. * @exception IOException if an I/O error occurs. */ public final FileDescriptor getFD() throws IOException { return file.getFD(); } /** * Copy the contents of the buffer to the disk. * * @exception IOException if an I/O error occurrs. */ public void flush() throws IOException { file.seek(bufferStart); file.write(buffer, 0, dataSize); bufferModified = false; } // // Read primitives. // /** * Read a byte of data from the file, blocking until data is available. * * @return the next byte of data, or -1 if the end of the file is reached. * @exception IOException if an I/O error occurrs. */ public final int read() throws IOException { // If the file position is within the data, return the byte... if (filePosition < dataEnd) { return (int) (buffer[(int) (filePosition++ - bufferStart)] & 0xff); // ...or should we indicate EOF... } else if (endOfFile) { return -1; // ...or seek to fill the buffer, and try again. } else { seek(filePosition); return read(); } } /** * Read up to * len bytes into an array, at a specified offset. This will * block until at least one byte has been read. * * @param b the byte array to receive the bytes. * @param off the offset in the array where copying will start. * @param len the number of bytes to copy. * @return the actual number of bytes read, or -1 if there is not more data * due to the end of the file being reached. * @exception IOException if an I/O error occurrs. */ private int readBytes(byte b[], int off, int len) throws IOException { // Check for end of file. if (endOfFile) { return -1; } // See how many bytes are available in the buffer - if none, // seek to the file position to update the buffer and try again. int bytesAvailable = (int) (dataEnd - filePosition); if (bytesAvailable < 1) { seek(filePosition); return readBytes(b, off, len); } // Copy as much as we can. int copyLength = (bytesAvailable >= len) ? len : bytesAvailable; System.arraycopy(buffer, (int) (filePosition - bufferStart), b, off, copyLength); filePosition += copyLength; // If there is more to copy... if (copyLength < len) { int extraCopy = len - copyLength; // If the amount remaining is more than a buffer's length, read it // directly from the file. if (extraCopy > buffer.length) { file.seek(filePosition); extraCopy = file.read(b, off + copyLength, len - copyLength); // ...or read a new buffer full, and copy as much as possible... } else { seek(filePosition); if (!endOfFile) { extraCopy = (extraCopy > dataSize) ? dataSize : extraCopy; System.arraycopy(buffer, 0, b, off + copyLength, extraCopy); } else { extraCopy = -1; } } // If we did manage to copy any more, update the file position and // return the amount copied. if (extraCopy > 0) { filePosition += extraCopy; return copyLength + extraCopy; } } // Return the amount copied. return copyLength; } /** * Read up to * len bytes into an array, at a specified offset. This will * block until at least one byte has been read. * * @param b the byte array to receive the bytes. * @param off the offset in the array where copying will start. * @param len the number of bytes to copy. * @return the actual number of bytes read, or -1 if there is not more data * due to the end of the file being reached. * @exception IOException if an I/O error occurrs. */ public int read(byte b[], int off, int len) throws IOException { return readBytes(b, off, len); } /** * Read up to * b.length( ) bytes into an array. This will block until at * least one byte has been read. * * @param b the byte array to receive the bytes. * @return the actual number of bytes read, or -1 if there is not more data * due to the end of the file being reached. * @exception IOException if an I/O error occurrs. */ public int read(byte b[]) throws IOException { return readBytes(b, 0, b.length); } /** * Reads * b.length bytes from this file into the byte array. This * method reads repeatedly from the file until all the bytes are read. This * method blocks until all the bytes are read, the end of the stream is * detected, or an exception is thrown. * * @param b the buffer into which the data is read. * @exception EOFException if this file reaches the end before reading all * the bytes. * @exception IOException if an I/O error occurs. */ public final void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); } /** * Reads exactly * len bytes from this file into the byte array. This method * reads repeatedly from the file until all the bytes are read. This method * blocks until all the bytes are read, the end of the stream is detected, * or an exception is thrown. * * @param b the buffer into which the data is read. * @param off the start offset of the data. * @param len the number of bytes to read. * @exception EOFException if this file reaches the end before reading all * the bytes. * @exception IOException if an I/O error occurs. */ public final void readFully(byte b[], int off, int len) throws IOException { int n = 0; while (n < len) { int count = this.read(b, off + n, len - n); if (count < 0) { throw new EOFException(); } n += count; } } /** * Skips exactly * n bytes of input. This method blocks until all the bytes are * skipped, the end of the stream is detected, or an exception is thrown. * * @param n the number of bytes to be skipped. * @return the number of bytes skipped, which is always n. * @exception EOFException if this file reaches the end before skipping all * the bytes. * @exception IOException if an I/O error occurs. */ public int skipBytes(int n) throws IOException { seek(getFilePointer() + n); return n; } /** * Unread the last byte read. This method should not be used more than once * between reading operations, or strange things might happen. */ public final void unread() { filePosition--; } // // Write primitives. // /** * Write a byte to the file. If the file has not been opened for writing, an * IOException will be raised only when an attempt is made to write the * buffer to the file.

Caveat: the effects of seek( )ing beyond the end * of the file are undefined. * * @exception IOException if an I/O error occurrs. */ public final void write(int b) throws IOException { // If the file position is within the block of data... if (filePosition < dataEnd) { buffer[(int) (filePosition++ - bufferStart)] = (byte) b; bufferModified = true; // ...or (assuming that seek will not allow the file pointer // to move beyond the end of the file) get the correct block of // data... } else { // If there is room in the buffer, expand it... if (dataSize != buffer.length) { buffer[(int) (filePosition++ - bufferStart)] = (byte) b; bufferModified = true; dataSize++; dataEnd++; // ...or do another seek to get a new buffer, and start again... } else { seek(filePosition); write(b); } } } /** * Write * len bytes from an array to the file. * * @param b the array containing the data. * @param off the offset in the array to the data. * @param len the length of the data. * @exception IOException if an I/O error occurrs. */ public final void writeBytes(byte b[], int off, int len) throws IOException { // If the amount of data is small (less than a full buffer)... if (len < buffer.length) { // If any of the data fits within the buffer... int spaceInBuffer = 0; int copyLength = 0; if (filePosition >= bufferStart) { spaceInBuffer = (int) ((bufferStart + buffer.length) - filePosition); } if (spaceInBuffer > 0) { // Copy as much as possible to the buffer. copyLength = (spaceInBuffer > len) ? len : spaceInBuffer; System.arraycopy(b, off, buffer, (int) (filePosition - bufferStart), copyLength); bufferModified = true; long myDataEnd = filePosition + copyLength; dataEnd = myDataEnd > dataEnd ? myDataEnd : dataEnd; dataSize = (int) (dataEnd - bufferStart); filePosition += copyLength; } // If there is any data remaining, move to the new position and copy to // the new buffer. if (copyLength < len) { seek(filePosition); System.arraycopy(b, off + copyLength, buffer, (int) (filePosition - bufferStart), len - copyLength); bufferModified = true; long myDataEnd = filePosition + (len - copyLength); dataEnd = myDataEnd > dataEnd ? myDataEnd : dataEnd; dataSize = (int) (dataEnd - bufferStart); filePosition += (len - copyLength); } // ...or write a lot of data... } else { // Flush the current buffer, and write this data to the file. if (bufferModified) { flush(); bufferStart = dataEnd = dataSize = 0; } file.write(b, off, len); filePosition += len; } } /** * Writes * b.length bytes from the specified byte array starting at * offset * off to this file. * * @param b the data. * @exception IOException if an I/O error occurs. */ public void write(byte b[]) throws IOException { writeBytes(b, 0, b.length); } /** * Writes * len bytes from the specified byte array starting at offset * off to this file. * * @param b the data. * @param off the start offset in the data. * @param len the number of bytes to write. * @exception IOException if an I/O error occurs. */ public void write(byte b[], int off, int len) throws IOException { writeBytes(b, off, len); } // // DataInput methods. // /** * Reads a * boolean from this file. This method reads a single byte from * the file. A value of * 0 represents * false. Any other value represents * true. This method blocks until the byte is read, the end of * the stream is detected, or an exception is thrown. * * @return the boolean value read. * @exception EOFException if this file has reached the end. * @exception IOException if an I/O error occurs. */ public final boolean readBoolean() throws IOException { int ch = this.read(); if (ch < 0) { throw new EOFException(); } return (ch != 0); } /** * Reads a signed 8-bit value from this file. This method reads a byte from * the file. If the byte read is * b, where * 0 <= b <= 255, then the result is:

    * (byte)(b) *

This method blocks until the byte is read, the end of * the stream is detected, or an exception is thrown. * * @return the next byte of this file as a signed 8-bit byte. * @exception EOFException if this file has reached the end. * @exception IOException if an I/O error occurs. */ public final byte readByte() throws IOException { int ch = this.read(); if (ch < 0) { throw new EOFException(); } return (byte) (ch); } /** * Reads an unsigned 8-bit number from this file. This method reads a byte * from this file and returns that byte.

This method blocks until the * byte is read, the end of the stream is detected, or an exception is * thrown. * * @return the next byte of this file, interpreted as an unsigned 8-bit * number. * @exception EOFException if this file has reached the end. * @exception IOException if an I/O error occurs. */ public final int readUnsignedByte() throws IOException { int ch = this.read(); if (ch < 0) { throw new EOFException(); } return ch; } /** * Reads a signed 16-bit number from this file. The method reads 2 bytes * from this file. If the two bytes read, in order, are * b1 and * b2, where each of the two values is between * 0 and * 255, inclusive, then the result is equal to:

    * (short)((b1 << 8) | b2) *

This method blocks until the two bytes are read, the end * of the stream is detected, or an exception is thrown. * * @return the next two bytes of this file, interpreted as a signed 16-bit * number. * @exception EOFException if this file reaches the end before reading two * bytes. * @exception IOException if an I/O error occurs. */ public final short readShort() throws IOException { int ch1 = this.read(); int ch2 = this.read(); if ((ch1 | ch2) < 0) { throw new EOFException(); } return (short) ((ch1 << 8) + (ch2 << 0)); } /** * Reads an unsigned 16-bit number from this file. This method reads two * bytes from the file. If the bytes read, in order, are * b1 and * b2, where * 0 <= b1, b2 <= 255, then the * result is equal to:

    * (b1 << 8) | b2 *

This method blocks until the two bytes are read, the end * of the stream is detected, or an exception is thrown. * * @return the next two bytes of this file, interpreted as an unsigned * 16-bit integer. * @exception EOFException if this file reaches the end before reading two * bytes. * @exception IOException if an I/O error occurs. */ public final int readUnsignedShort() throws IOException { int ch1 = this.read(); int ch2 = this.read(); if ((ch1 | ch2) < 0) { throw new EOFException(); } return (ch1 << 8) + (ch2 << 0); } /** * Reads a Unicode character from this file. This method reads two bytes * from the file. If the bytes read, in order, are * b1 and * b2, where * 0 <= b1, b2 <= 255, then the * result is equal to:

    * (char)((b1 << 8) | b2) *

This method blocks until the two bytes are read, the end * of the stream is detected, or an exception is thrown. * * @return the next two bytes of this file as a Unicode character. * @exception EOFException if this file reaches the end before reading two * bytes. * @exception IOException if an I/O error occurs. */ public final char readChar() throws IOException { int ch1 = this.read(); int ch2 = this.read(); if ((ch1 | ch2) < 0) { throw new EOFException(); } return (char) ((ch1 << 8) + (ch2 << 0)); } /** * Reads a signed 32-bit integer from this file. This method reads 4 bytes * from the file. If the bytes read, in order, are * b1, * b2, * b3, and * b4, where * 0 <= b1, b2, b3, b4 <= 255, then * the result is equal to:

    * (b1 << 24) | (b2 << 16) + (b3 << 8) + b4 *

This method blocks until the four bytes are read, the * end of the stream is detected, or an exception is thrown. * * @return the next four bytes of this file, interpreted as an * int. * @exception EOFException if this file reaches the end before reading four * bytes. * @exception IOException if an I/O error occurs. */ public final int readInt() throws IOException { int ch1 = this.read(); int ch2 = this.read(); int ch3 = this.read(); int ch4 = this.read(); if ((ch1 | ch2 | ch3 | ch4) < 0) { throw new EOFException(); } return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); } /** * Reads a signed 64-bit integer from this file. This method reads eight * bytes from the file. If the bytes read, in order, are * b1, * b2, * b3, * b4, * b5, * b6, * b7, and * b8, where:

    * 0 <= b1, b2, b3, b4, b5, b6, b7, b8 <=255, *

then the result is equal to:

    *     ((long)b1 << 56) + ((long)b2 << 48)
     *     + ((long)b3 << 40) + ((long)b4 << 32)
     *     + ((long)b5 << 24) + ((long)b6 << 16)
     *     + ((long)b7 << 8) + b8
     * 

This method blocks until the eight bytes are * read, the end of the stream is detected, or an exception is thrown. * * @return the next eight bytes of this file, interpreted as a * long. * @exception EOFException if this file reaches the end before reading eight * bytes. * @exception IOException if an I/O error occurs. */ public final long readLong() throws IOException { return ((long) (readInt()) << 32) + (readInt() & 0xFFFFFFFFL); } /** * Reads a * float from this file. This method reads an * int value as if by the * readInt method and then converts that * int to a * float using the * intBitsToFloat method in class * Float.

This method blocks until the four bytes are read, * the end of the stream is detected, or an exception is thrown. * * @return the next four bytes of this file, interpreted as a * float. * @exception EOFException if this file reaches the end before reading four * bytes. * @exception IOException if an I/O error occurs. * @see java.io.RandomAccessFile#readInt() * @see java.lang.Float#intBitsToFloat(int) */ public final float readFloat() throws IOException { return Float.intBitsToFloat(readInt()); } /** * Reads a * double from this file. This method reads a * long value as if by the * readLong method and then converts that * long to a * double using the * longBitsToDouble method in class * Double.

This method blocks until the eight bytes are * read, the end of the stream is detected, or an exception is thrown. * * @return the next eight bytes of this file, interpreted as a * double. * @exception EOFException if this file reaches the end before reading eight * bytes. * @exception IOException if an I/O error occurs. * @see java.io.RandomAccessFile#readLong() * @see java.lang.Double#longBitsToDouble(long) */ public final double readDouble() throws IOException { return Double.longBitsToDouble(readLong()); } /** * Reads the next line of text from this file. This method successively * reads bytes from the file until it reaches the end of a line of text.

* A line of text is terminated by a carriage-return character * ( * '\r'), a newline character ( * '\n'), a carriage-return character immediately followed * by a newline character, or the end of the input stream. The * line-terminating character(s), if any, are included as part of the string * returned.

This method blocks until a newline character is read, a * carriage return and the byte following it are read (to see if it is a * newline), the end of the stream is detected, or an exception is thrown. * * @return the next line of text from this file. * @exception IOException if an I/O error occurs. */ public final String readLine() throws IOException { StringBuffer input = new StringBuffer(); int c; while (((c = read()) != -1) && (c != '\n')) { input.append((char) c); } if ((c == -1) && (input.length() == 0)) { return null; } return input.toString(); } /** * Reads in a string from this file. The string has been encoded using a * modified UTF-8 format.

The first two bytes are read as if by * readUnsignedShort. This value gives the number of following * bytes that are in the encoded string, not the length of the resulting * string. The following bytes are then interpreted as bytes encoding * characters in the UTF-8 format and are converted into characters.

* This method blocks until all the bytes are read, the end of the stream is * detected, or an exception is thrown. * * @return a Unicode string. * @exception EOFException if this file reaches the end before reading all * the bytes. * @exception IOException if an I/O error occurs. * @exception UTFDataFormatException if the bytes do not represent valid * UTF-8 encoding of a Unicode string. * @see java.io.RandomAccessFile#readUnsignedShort() */ public final String readUTF() throws IOException { return DataInputStream.readUTF(this); } // // DataOutput methods. // /** * Writes a * boolean to the file as a 1-byte value. The value * true is written out as the value * (byte)1; the value * false is written out as the value * (byte)0. * * @param v a boolean value to be written. * @exception IOException if an I/O error occurs. */ public final void writeBoolean(boolean v) throws IOException { write(v ? 1 : 0); } /** * Writes a * byte to the file as a 1-byte value. * * @param v a byte value to be written. * @exception IOException if an I/O error occurs. */ public final void writeByte(int v) throws IOException { write(v); } /** * Writes a * short to the file as two bytes, high byte first. * * @param v a short to be written. * @exception IOException if an I/O error occurs. */ public final void writeShort(int v) throws IOException { write((v >>> 8) & 0xFF); write((v >>> 0) & 0xFF); } /** * Writes a * char to the file as a 2-byte value, high byte first. * * @param v a char value to be written. * @exception IOException if an I/O error occurs. */ public final void writeChar(int v) throws IOException { write((v >>> 8) & 0xFF); write((v >>> 0) & 0xFF); } /** * Writes an * int to the file as four bytes, high byte first. * * @param v an int to be written. * @exception IOException if an I/O error occurs. */ public final void writeInt(int v) throws IOException { write((v >>> 24) & 0xFF); write((v >>> 16) & 0xFF); write((v >>> 8) & 0xFF); write((v >>> 0) & 0xFF); } /** * Writes a * long to the file as eight bytes, high byte first. * * @param v a long to be written. * @exception IOException if an I/O error occurs. */ public final void writeLong(long v) throws IOException { write((int) (v >>> 56) & 0xFF); write((int) (v >>> 48) & 0xFF); write((int) (v >>> 40) & 0xFF); write((int) (v >>> 32) & 0xFF); write((int) (v >>> 24) & 0xFF); write((int) (v >>> 16) & 0xFF); write((int) (v >>> 8) & 0xFF); write((int) (v >>> 0) & 0xFF); } /** * Converts the float argument to an * int using the * floatToIntBits method in class * Float, and then writes that * int value to the file as a 4-byte quantity, high byte first. * * @param v a float value to be written. * @exception IOException if an I/O error occurs. * @see java.lang.Float#floatToIntBits(float) */ public final void writeFloat(float v) throws IOException { writeInt(Float.floatToIntBits(v)); } /** * Converts the double argument to a * long using the * doubleToLongBits method in class * Double, and then writes that * long value to the file as an 8-byte quantity, high byte * first. * * @param v a double value to be written. * @exception IOException if an I/O error occurs. * @see java.lang.Double#doubleToLongBits(double) */ public final void writeDouble(double v) throws IOException { writeLong(Double.doubleToLongBits(v)); } /** * Writes the string to the file as a sequence of bytes. Each character in * the string is written out, in sequence, by discarding its high eight * bits. * * @param s a string of bytes to be written. * @exception IOException if an I/O error occurs. */ public final void writeBytes(String s) throws IOException { int len = s.length(); for (int i = 0; i < len; i++) { write((byte) s.charAt(i)); } } /** * Writes the character array to the file as a sequence of bytes. Each * character in the string is written out, in sequence, by discarding its * high eight bits. * * @param b a character array of bytes to be written. * @param off the index of the first character to write. * @param len the number of characters to write. * @exception IOException if an I/O error occurs. */ public final void writeBytes(char b[], int off, int len) throws IOException { for (int i = off; i < len; i++) { write((byte) b[i]); } } /** * Writes a string to the file as a sequence of characters. Each character * is written to the data output stream as if by the * writeChar method. * * @param s a String value to be written. * @exception IOException if an I/O error occurs. * @see java.io.RandomAccessFile#writeChar(int) */ public final void writeChars(String s) throws IOException { int len = s.length(); for (int i = 0; i < len; i++) { int v = s.charAt(i); write((v >>> 8) & 0xFF); write((v >>> 0) & 0xFF); } } /** * Writes a string to the file using UTF-8 encoding in a machine-independent * manner.

First, two bytes are written to the file as if by the * writeShort method giving the number of bytes to follow. This * value is the number of bytes actually written out, not the length of the * string. Following the length, each character of the string is output, in * sequence, using the UTF-8 encoding for each character. * * @param str a string to be written. * @exception IOException if an I/O error occurs. */ public final void writeUTF(String str) throws IOException { int strlen = str.length(); int utflen = 0; for (int i = 0; i < strlen; i++) { int c = str.charAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { utflen++; } else if (c > 0x07FF) { utflen += 3; } else { utflen += 2; } } if (utflen > 65535) { throw new UTFDataFormatException(); } write((utflen >>> 8) & 0xFF); write((utflen >>> 0) & 0xFF); for (int i = 0; i < strlen; i++) { int c = str.charAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { write(c); } else if (c > 0x07FF) { write(0xE0 | ((c >> 12) & 0x0F)); write(0x80 | ((c >> 6) & 0x3F)); write(0x80 | ((c >> 0) & 0x3F)); } else { write(0xC0 | ((c >> 6) & 0x1F)); write(0x80 | ((c >> 0) & 0x3F)); } } } /** * Create a string representation of this object. * * @return a string representation of the state of the object. */ public String toString() { return "fp=" + filePosition + ", bs=" + bufferStart + ", de=" + dataEnd + ", ds=" + dataSize + ", bl=" + buffer.length + ", m=" + mode + ", bm=" + bufferModified; } /** * Test the byte operations of the RandomAccessFile class. These are the * methods that read/write on a byte-by-byte basis. The following checks are * made:

  • Writing random bytes to a file.
  • Checking the size of * the file is correct.
  • Checking that EOF is correctly raised. *
  • Reading the file back in and verifying its contents.
The test * file is 4.5 times the size of the buffer, in order to test paging between * buffers, and using files that end in the middle of a buffer. A constant * seed value is used for the random number generator, to ensure any bugs * are reproduceable. * * @param filename the name of the test file to generate. * @param bufferSize the size of the buffer to use. */ public static void testBytes(String filename, int bufferSize) { System.out.println("\nTesting byte operations..."); int newFileSize = (int) (bufferSize * 4.5); try { // Create a test file. RandomAccessFile outFile = new RandomAccessFile(filename, RandomAccessFile.WRITE | RandomAccessFile.CREATE, bufferSize); try { Random random = new Random(0); byte b = 0; for (int i = 0; i < newFileSize; i++) { b = (byte) (random.nextInt() % 256); outFile.writeByte(b); } } finally { outFile.close(); } // Check that the file length is correct. if ((new File(filename)).length() == newFileSize) { System.out.println(". File size correct (" + newFileSize + ")."); } else { System.out.println("X New file size incorrect (should be " + newFileSize + ", but is " + (new File(filename)).length() + ")."); } // Read the file, verify and modify its contents. RandomAccessFile inoutFile = new RandomAccessFile(filename, RandomAccessFile.READ | RandomAccessFile.WRITE, bufferSize); boolean verified = true; int byteNo = 0; try { // Read each byte in the file. Random random = new Random(0); byte b = 0; for (byteNo = 0; byteNo < newFileSize; byteNo++) { b = (byte) (random.nextInt() % 256); byte currentByte = inoutFile.readByte(); // Check the value is correct. if (currentByte != b) { verified = false; } // Modify selected values. if (currentByte >= 128) { inoutFile.seek(inoutFile.getFilePointer() - 1); inoutFile.writeByte(0); } } // Check the EOF is correctly trapped. boolean foundEOF = false; try { inoutFile.readByte(); } catch (EOFException e) { foundEOF = true; } if (foundEOF) { System.err.println(". EOF found correctly"); } else { System.err.println("X No EOF found."); } // Trace a premature EOF. } catch (EOFException e) { e.printStackTrace(); System.err.println(" At byte " + byteNo); } finally { inoutFile.close(); } // Check that the read was verified. if (verified) { System.out.println(". Read/Write verified"); } else { System.out.println("X Read/Write verification failed"); } // Read the file and verify contents. RandomAccessFile inFile = new RandomAccessFile(filename, RandomAccessFile.READ, bufferSize); verified = true; byteNo = 0; try { // Read each byte in the file. Random random = new Random(0); byte b = 0; for (byteNo = 0; byteNo < newFileSize; byteNo++) { b = (byte) (random.nextInt() % 256); byte currentByte = inFile.readByte(); // Account for the modification. if (currentByte >= 128) { currentByte = 0; } // Check the byte's value. if (currentByte != b) { verified = false; } } // Trap a premature EOF. } catch (EOFException e) { e.printStackTrace(); System.err.println(" At byte " + byteNo); } finally { inFile.close(); } // Check that the read was verified. if (verified) { System.out.println(". Update verified"); } else { System.out.println("X Update verification failed"); } } catch (Exception e) { e.printStackTrace(); } } /** * Test the block operations of the RandomAccessFile class. These are the * methods that read/write blocks of data. The following checks are made: *
  • Writing blocks of data that are smaller than the buffer size. *
  • Writing blocks of data that are larger than the buffer size. *
  • Checking the size of the file is correct.
  • Reading small blocks of * the file back in and verifying its contents.
  • Reading large blocks of * the file back in and verifying its contents.
* * @param filename the name of the test file to generate. */ public static void testBlocks(String filename) { System.err.println("\nTesting block operations..."); // Generate the data. int bufferSize = 10; byte data[] = new byte[256]; for (int i = 0; i < data.length; i++) { data[i] = (byte) (i % 256); } try { // Write the data in small and large blocks. RandomAccessFile outFile = new RandomAccessFile( filename, RandomAccessFile.WRITE | RandomAccessFile.CREATE, bufferSize); for (int i = 0; i < data.length;) { int blockSize = (i < data.length / 2) ? 3 : 13; blockSize = (i + blockSize >= data.length) ? (data.length - i) : blockSize; outFile.write(data, i, blockSize); i += blockSize; } outFile.close(); // Check that the file length is correct. if ((new File(filename)).length() != data.length) { System.out.println("X New file size incorrect (should be " + data.length + ", but is " + (new File(filename)).length() + ")."); } else { System.out.println(". File size correct (" + data.length + ")."); } // Reopen the file for reading. RandomAccessFile inFile = new RandomAccessFile( filename, RandomAccessFile.READ, bufferSize); // Read and check random small blocks of data. boolean verified = true; int firstFailure = 256; Random random = new Random(0); byte block[] = new byte[(int) (bufferSize * 0.5)]; for (int i = 0; i < 100; i++) { int index = Math.abs(random.nextInt()) % (data.length - block.length); inFile.seek(index); inFile.read(block); // Verify the block of data. for (int j = 0; j < block.length; j++) { if (block[j] != data[index + j]) { verified = false; if (index + j < firstFailure) { firstFailure = index + j; } } } } if (verified) { System.err.println(". Reading small blocks verified."); } else { System.err.println("X Reading small blocks failed (byte " + firstFailure + ")."); } // Read and check random large (bigger than the bufferSize) blocks // of data. verified = true; random = new Random(0); block = new byte[(int) (bufferSize * 1.5)]; for (int i = 0; i < 100; i++) { int index = Math.abs(random.nextInt()) % (data.length - block.length); inFile.seek(index); inFile.read(block); // Verify the block of data. for (int j = 0; j < block.length; j++) { if (block[j] != data[j + index]) { verified = false; } } } if (verified) { System.err.println(". Reading large blocks verified."); } else { System.err.println("X Reading large blocks failed."); } // Close the input file. inFile.close(); } catch (Exception e) { e.printStackTrace(); } } /** * Benchmark the performance of the new RandomAccessFile class. Its speed is * compared to that of a java.io.RandomAccessFile, based on reading and * writing a test file, byte by byte. * * @param filename the name of the test file. * @param bufferSize the buffer size to use. */ public static void benchmark(String filename, int bufferSize) { System.out.println("\nBenchmarking..."); // Start the clock, and open a file for reading and a file for writing. long time = (new Date()).getTime(); try { RandomAccessFile inFile = new RandomAccessFile(filename, RandomAccessFile.READ, bufferSize); RandomAccessFile outFile = new RandomAccessFile("temp.data", RandomAccessFile.WRITE | RandomAccessFile.CREATE, bufferSize); // Copy one file to the other. try { while (true) { outFile.writeByte(inFile.readByte()); } } catch (EOFException e) { } catch (IOException e) { e.printStackTrace(); } finally { inFile.close(); outFile.close(); } System.out.println(". RandomAccessFile elapsed time=" + ((new Date()).getTime() - time)); // Restart the clock, and open RandomAccessFiles for reading and writing. time = (new Date()).getTime(); java.io.RandomAccessFile inFile2 = new java.io.RandomAccessFile(filename, "r"); java.io.RandomAccessFile outFile2 = new java.io.RandomAccessFile("temp.data", "rw"); // Copy one file to the other. try { while (true) { outFile2.writeByte(inFile2.readByte()); } } catch (EOFException e) { } catch (IOException e) { e.printStackTrace(); } finally { inFile2.close(); outFile2.close(); } } catch (Exception e) { e.printStackTrace(); } System.out.println(". java.io.RandomAccessFile elapsed time=" + ((new Date()).getTime() - time)); } // /** // * Test the RandomAccessFile class. This involves testing the byte methods, // * the block methods, and benchmarking the performance. By appending 'test' // * or 'benchmark' to the command-line, it can be limited to the tests or // * benchmarking alone. The test filename is only used for the benchmarking, // * the other tests create a file called "temp.data" in the current // * directory. Note that the size of the buffer determines the size of the // * test file (which is 4.5 times the size of the buffer). // * // * @param argv Usage: [bufferSize] [test | benchmark] // * @see testBytes // * @see testBlocks // * @see benchmark // */ // public static void main(String argv[]) { // // int defaultPageSize = 4096; // // // Parse the command-line arguments. // String filename = null; // int bufferSize = 0; // boolean test = true; // boolean benchmark = true; // if (argv.length < 1) { // System.err.println("Usage: RandomAccessFile [buffer.length] [benchmark | test]"); // System.exit(-1); // } else if (argv.length < 2) { // filename = argv[0]; // bufferSize = defaultPageSize; // } else if (argv.length < 3) { // filename = argv[0]; // bufferSize = Integer.parseInt(argv[1]); // } else { // filename = argv[0]; // bufferSize = Integer.parseInt(argv[1]); // if (argv[2].equals("benchmark")) { // test = false; // } else if (argv[2].equals("test")) { // benchmark = false; // } // } // // System.out.println("\nRandomAccessFile\n" // + "========================"); // System.out.println("filename=" + filename // + ", bufferSize=" + bufferSize); // System.out.println("totalMemory=" // + (Runtime.getRuntime().totalMemory() / 1000) + "k" // + " freeMemory=" + (Runtime.getRuntime().freeMemory() / 1000) + "k"); // // if (test) { // RandomAccessFile.testBytes("temp.data", bufferSize); // RandomAccessFile.testBlocks("temp.data"); // } // if (benchmark) { // RandomAccessFile.benchmark(filename, bufferSize); // } // // System.out.println("\nEND"); // } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy