Mega Code Archive

 
Categories / Java / Development Class
 

A random access text file allows a text file to be accessed randomly starting at any position

/*  * RandomAccessFile.java Created Aug 24, 2010 by Andrew Butler, PSL  */ //package prisms.util; import java.io.IOException; /**  * A random access text file allows a text file to be accessed randomly starting  * at any position. It keeps a buffer of a configurable length, enabling  * successive access operations to be as efficient as possible.  */ public class RandomAccessTextFile {   class CircularCharBuffer {     private char[] theBuffer;     private int start;     private int end;     private int pos;     CircularCharBuffer(int length) {       theBuffer = new char[length];     }     void resize(int size) {       char[] newBuffer = new char[size];       boolean rotated = start <= end;       int newPos = 0;       for (int i = start; (i < end || !rotated)           && newPos < newBuffer.length; i++, newPos++) {         if (i == theBuffer.length) {           i = 0;           rotated = true;         }         int tempPos = i - start;         if (tempPos < 0)           tempPos += theBuffer.length;         newBuffer[tempPos] = theBuffer[i];       }       end -= start;       if (end < 0)         end += theBuffer.length;       pos -= start;       if (pos < 0)         pos += theBuffer.length;       start = 0;       theBuffer = newBuffer;     }     void add(char c) {       theBuffer[pos] = c;       pos++;       if (pos == theBuffer.length)         pos = 0;       end = pos;       if (start == end)         start++;     }     char get() {       return theBuffer[pos++];     }     int getPos() {       int ret = pos - start;       if (ret < 0)         ret += theBuffer.length;       return ret;     }     int getRemaining() {       int ret = end - pos;       if (ret < 0)         ret += theBuffer.length;       if (ret >= getLength())         return 0;       return ret;     }     int getLength() {       int ret = end - start;       if (ret < 0)         ret += theBuffer.length;       return ret;     }     void reset() {       start = end = pos = 0;     }     void move(int dist) {       int newPos = pos + dist;       if (dist < 0) {         if (-dist > getPos()) {           reset();           return;         }         if (newPos < 0)           newPos += theBuffer.length;       } else {         if (dist >= getRemaining()) {           reset();           return;         }         if (newPos >= theBuffer.length)           newPos -= theBuffer.length;       }       pos = newPos;     }     void clear() {       theBuffer = null;     }   }   /**    * A reader that reads a file from a given position, keeping a buffer for    * efficient operation when moving positions    */   public class RandomAccessReader extends java.io.Reader {     private int thePos;     private java.io.FileReader theFileReader;     private int theReaderIndex;     private CircularCharBuffer theBuffer;     RandomAccessReader(int length) {       theBuffer = new CircularCharBuffer(length);     }     @Override     public int read(char[] cbuf, int off, int len) throws IOException {       int rem = theBuffer.getRemaining();       for (int i = 0; i < rem && i < len; i++)         cbuf[off + i] = theBuffer.get();       int count = rem < len ? rem : len;       thePos += count;       if (rem < len) {         if (theFileReader == null || theReaderIndex != thePos)           resetReader();         count += theFileReader.read(cbuf, off + count, len - count);         theReaderIndex += count - rem;         thePos += count - rem;         for (int i = rem + off; i < off + count; i++)           theBuffer.add(cbuf[i]);       }       return count;     }     /**      * Does nothing. No resources are released here in case of further      * {@link RandomAccessTextFile#access} operations. Use      * {@link RandomAccessTextFile#close(boolean)} when done with the random      * access file in general.      */     @Override     public void close() throws IOException {     }     /**      * Resets this reader's internal reader to start at this reader's      * current position      */     private void resetReader() throws IOException {       if (theFileReader != null)         theFileReader.close();       theFileReader = new java.io.FileReader(theFile);       theFileReader.skip(thePos);       theReaderIndex = thePos;     }     void move(int pos) {       theBuffer.move(pos - thePos);       thePos = pos;     }     void setBufferLength(int length) {       theBuffer.resize(length);     }     void reallyClose() throws IOException {       theBuffer.clear();       if (theFileReader != null)         theFileReader.close();     }   }   java.io.File theFile;   private RandomAccessReader theReader;   /**    * Creates a random access file for a given file    *     * @param file    *            The file to access randomly    */   public RandomAccessTextFile(java.io.File file) {     this(file, 10240);   }   /**    * Creates a random access file for a given file and buffer length    *     * @param file    *            The file to access randomly    * @param bufferLength    *            The length of the buffer to keep, making random access quicker    */   public RandomAccessTextFile(java.io.File file, int bufferLength) {     theFile = file;     theReader = new RandomAccessReader(bufferLength);   }   /**    * @param length    *            The length of the buffer to keep    */   public void setBufferLength(int length) {     theReader.setBufferLength(length);   }   /**    * @param position    *            The position to start reading this file at    * @return A reader that reads the content of this file from the given    *         position    * @throws java.io.IOException    *             If an exception occurs reading the file to the given position    */   public RandomAccessReader access(int position) throws java.io.IOException {     theReader.move(position);     return theReader;   }   /**    * @return The file that this wrapper accesses    */   public java.io.File getFile() {     return theFile;   }   /**    * Closes this file, releasing all resources    *     * @param deleteFile    *            Whether to delete the text file    * @throws IOException    *             If an error occurs releasing the resources    */   public void close(boolean deleteFile) throws IOException {     theReader.reallyClose();     if (deleteFile)       theFile.delete();     theFile = null;   } }