FileSeekableStream.java
上传用户:btjssb159
上传日期:2018-01-04
资源大小:241k
文件大小:8k
源码类别:

DNA

开发平台:

Java

  1. /*
  2.  * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without 
  5.  * modification, are permitted provided that the following conditions are met:
  6.  * 
  7.  * -Redistributions of source code must retain the above copyright notice, this 
  8.  * list of conditions and the following disclaimer.
  9.  *
  10.  * -Redistribution in binary form must reproduct the above copyright notice,
  11.  * this list of conditions and the following disclaimer in the documentation
  12.  * and/or other materials provided with the distribution.
  13.  * 
  14.  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
  15.  * be used to endorse or promote products derived from this software without
  16.  * specific prior written permission.
  17.  * 
  18.  * This software is provided "AS IS," without a warranty of any kind. ALL
  19.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
  20.  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
  21.  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
  22.  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  23.  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
  24.  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
  25.  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
  26.  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
  27.  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
  28.  * POSSIBILITY OF SUCH DAMAGES.
  29.  * 
  30.  * You acknowledge that Software is not designed,licensed or intended for use in 
  31.  * the design, construction, operation or maintenance of any nuclear facility.
  32.  */
  33. import java.io.File;
  34. import java.io.IOException;
  35. import java.io.RandomAccessFile;
  36. /**
  37.  * A subclass of <code>SeekableStream</code> that takes its input
  38.  * from a <code>File</code> or <code>RandomAccessFile</code>.
  39.  * Backwards seeking is supported.  The <code>mark()</code> and
  40.  * <code>resest()</code> methods are supported.
  41.  *
  42.  * <p><b> This class is not a committed part of the JAI API.  It may
  43.  * be removed or changed in future releases of JAI.</b>
  44.  */
  45. public class FileSeekableStream extends SeekableStream {
  46.     
  47.     private RandomAccessFile file;
  48.     private long markPos = -1;
  49.     // Base 2 logarithm of the cache page size
  50.     private static final int PAGE_SHIFT = 9;
  51.     // The page size, derived from PAGE_SHIFT
  52.     private static final int PAGE_SIZE = 1 << PAGE_SHIFT;
  53.     // Binary mask to find the offset of a pointer within a cache page
  54.     private static final int PAGE_MASK = PAGE_SIZE - 1;
  55.     // Number of pages to cache
  56.     private static final int NUM_PAGES = 32;
  57.     // Reads longer than this bypass the cache
  58.     private static final int READ_CACHE_LIMIT = PAGE_SIZE;
  59.     // The page cache
  60.     private byte[][] pageBuf = new byte[PAGE_SIZE][NUM_PAGES];
  61.     
  62.     // The index of the file page held in a given cache entry,
  63.     // -1 = invalid.
  64.     private int[] currentPage = new int[NUM_PAGES];
  65.     private long length = 0L;
  66.     private long pointer = 0L;
  67.     /**
  68.      * Constructs a <code>FileSeekableStream</code> from a 
  69.      * <code>RandomAccessFile</code>.
  70.      */
  71.     public FileSeekableStream(RandomAccessFile file) throws IOException {
  72.         this.file = file;
  73.         file.seek(0L);
  74.         this.length = file.length();
  75.         // Allocate the cache pages and mark them as invalid
  76.         for (int i = 0; i < NUM_PAGES; i++) {
  77.             pageBuf[i] = new byte[PAGE_SIZE];
  78.             currentPage[i] = -1;
  79.         }
  80.     }
  81.     /**
  82.      * Constructs a <code>FileSeekableStream</code> from a 
  83.      * <code>File</code>.
  84.      */
  85.     public FileSeekableStream(File file) throws IOException {
  86.         this(new RandomAccessFile(file, "r"));
  87.     }
  88.     /**
  89.      * Constructs a <code>FileSeekableStream</code> from a 
  90.      * <code>String</code> path name.
  91.      */
  92.     public FileSeekableStream(String name) throws IOException {
  93.         this(new RandomAccessFile(name, "r"));
  94.     }
  95.     /** Returns true since seeking backwards is supported. */
  96.     public final boolean canSeekBackwards() {
  97.         return true;
  98.     }
  99.     /**
  100.      * Returns the current offset in this stream.
  101.      *
  102.      * @return     the offset from the beginning of the stream, in bytes,
  103.      *             at which the next read occurs.
  104.      * @exception  IOException  if an I/O error occurs.
  105.      */
  106.     public final long getFilePointer() throws IOException {
  107.         return pointer;
  108.     }
  109.     public final void seek(long pos) throws IOException {
  110.         if (pos < 0) {
  111.             throw new IOException(JaiI18N.getString("FileSeekableStream0"));
  112.         }
  113.         pointer = pos;
  114.     }
  115.     public final int skip(int n) throws IOException {
  116.         pointer += n;
  117.         return n;
  118.     }
  119.     private byte[] readPage(long pointer) throws IOException {
  120.         int page = (int)(pointer >> PAGE_SHIFT);
  121.         for (int i = 0; i < NUM_PAGES; i++) {
  122.             if (currentPage[i] == page) {
  123.                 return pageBuf[i];
  124.             }
  125.         }
  126.         // Use random replacement for now
  127.         int index = (int)(Math.random()*NUM_PAGES);
  128.         currentPage[index] = page;
  129.         long pos = ((long)page) << PAGE_SHIFT;
  130.         long remaining = length - pos;
  131.         int len = PAGE_SIZE < remaining ? PAGE_SIZE : (int)remaining;
  132.         file.seek(pos);
  133.         file.readFully(pageBuf[index], 0, len);
  134.         return pageBuf[index];
  135.     }
  136.     /** Forwards the request to the real <code>File</code>. */
  137.     public final int read() throws IOException {
  138.         if (pointer >= length) {
  139.             return -1;
  140.         }
  141.         byte[] buf = readPage(pointer);
  142.         return buf[(int)(pointer++ & PAGE_MASK)] & 0xff;
  143.     }
  144.     /** Forwards the request to the real <code>File</code>. */
  145.     public final int read(byte[] b, int off, int len) throws IOException {
  146.         if (b == null) {
  147.             throw new NullPointerException();
  148.         }
  149.         if ((off < 0) || (len < 0) || (off + len > b.length)) {
  150.             throw new IndexOutOfBoundsException();
  151.         }
  152.         if (len == 0) {
  153.             return 0;
  154.         }
  155.         len = (int)Math.min((long)len, length - pointer);
  156.         if (len <= 0) {
  157.             return -1;
  158.         }
  159.         // If the read is large, don't bother to cache it.
  160.         if (len > READ_CACHE_LIMIT) {
  161.             file.seek(pointer);
  162.             int nbytes = file.read(b, off, len);
  163.             pointer += nbytes;
  164.             return nbytes;
  165.         } else {
  166.             byte[] buf = readPage(pointer);
  167.         
  168.             // Compute length to end of page
  169.             int remaining = PAGE_SIZE - (int)(pointer & PAGE_MASK);
  170.             int newLen = len < remaining ? len : remaining;
  171.             System.arraycopy(buf, (int)(pointer & PAGE_MASK), b, off, newLen);
  172.             
  173.             pointer += newLen;
  174.             return newLen;
  175.         }
  176.     }
  177.     /** Forwards the request to the real <code>File</code>. */
  178.     public final void close() throws IOException {
  179.         file.close();
  180.     }
  181.     /**
  182.      * Marks the current file position for later return using
  183.      * the <code>reset()</code> method.
  184.      */
  185.     public synchronized final void mark(int readLimit) {
  186.         markPos = pointer;
  187.     }
  188.     /**
  189.      * Returns the file position to its position at the time of
  190.      * the immediately previous call to the <code>mark()</code>
  191.      * method.
  192.      */
  193.     public synchronized final void reset() throws IOException {
  194.         if (markPos != -1) {
  195.             pointer = markPos;
  196.         }
  197.     }
  198.     /** Returns <code>true</code> since marking is supported. */
  199.     public boolean markSupported() {
  200.         return true;
  201.     }
  202. }