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

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.FileInputStream;
  35. import java.io.InputStream;
  36. import java.io.IOException;
  37. import java.io.RandomAccessFile;
  38. /**
  39.  * A subclass of <code>SeekableStream</code> that may be used to wrap
  40.  * a regular <code>InputStream</code>.  Seeking backwards is supported
  41.  * by means of a file cache.  In circumstances that do not allow the
  42.  * creation of a temporary file (for example, due to security
  43.  * consideration or the absence of local disk), the
  44.  * <code>MemoryCacheSeekableStream</code> class may be used instead.
  45.  *
  46.  * <p> The <code>mark()</code> and <code>reset()</code> methods are
  47.  * supported.
  48.  *
  49.  * <p><b> This class is not a committed part of the JAI API.  It may
  50.  * be removed or changed in future releases of JAI.</b>
  51.  */
  52. public final class FileCacheSeekableStream extends SeekableStream {
  53.     /** The source stream. */
  54.     private InputStream stream;
  55.     /** The cache File. */
  56.     private File cacheFile;
  57.     /** The cache as a RandomAcessFile. */
  58.     private RandomAccessFile cache;
  59.     /** The length of the read buffer. */
  60.     private int bufLen = 1024;
  61.     /** The read buffer. */
  62.     private byte[] buf = new byte[bufLen];
  63.     /** Number of bytes in the cache. */
  64.     private long length = 0;
  65.     /** Next byte to be read. */
  66.     private long pointer = 0;
  67.     /** True if we've encountered the end of the source stream. */
  68.     private boolean foundEOF = false;
  69.     /**
  70.      * Constructs a <code>MemoryCacheSeekableStream</code> that takes
  71.      * its source data from a regular <code>InputStream</code>.
  72.      * Seeking backwards is supported by means of an file cache.
  73.      *
  74.      * <p> An <code>IOException</code> will be thrown if the
  75.      * attempt to create the cache file fails for any reason.
  76.      */
  77.     public FileCacheSeekableStream(InputStream stream) 
  78.         throws IOException {
  79.         this.stream = stream;
  80.         this.cacheFile = File.createTempFile("jai-FCSS-", ".tmp");
  81.         cacheFile.deleteOnExit();
  82.         this.cache = new RandomAccessFile(cacheFile, "rw");
  83.     }
  84.     /**
  85.      * Ensures that at least <code>pos</code> bytes are cached,
  86.      * or the end of the source is reached.  The return value
  87.      * is equal to the smaller of <code>pos</code> and the
  88.      * length of the source file.
  89.      */
  90.     private long readUntil(long pos) throws IOException {
  91.         // We've already got enough data cached
  92.         if (pos < length) {
  93.             return pos;
  94.         }
  95.         // pos >= length but length isn't getting any bigger, so return it
  96.         if (foundEOF) {
  97.             return length;
  98.         }
  99.         long len = pos - length;
  100.         cache.seek(length);
  101.         while (len > 0) {
  102.             // Copy a buffer's worth of data from the source to the cache
  103.             // bufLen will always fit into an int so this is safe
  104.             int nbytes = stream.read(buf, 0, (int)Math.min(len, (long)bufLen));
  105.             if (nbytes == -1) {
  106.                 foundEOF = true;
  107.                 return length;
  108.             }
  109.             cache.setLength(cache.length() + nbytes);
  110.             cache.write(buf, 0, nbytes);
  111.             len -= nbytes;
  112.             length += nbytes;
  113.         }
  114.         return pos;
  115.     }
  116.     /**
  117.      * Returns <code>true</code> since all
  118.      * <code>FileCacheSeekableStream</code> instances support seeking
  119.      * backwards.
  120.      */
  121.     public boolean canSeekBackwards() {
  122.         return true;
  123.     }
  124.     /**
  125.      * Returns the current offset in this file. 
  126.      *
  127.      * @return     the offset from the beginning of the file, in bytes,
  128.      *             at which the next read occurs.
  129.      */
  130.     public long getFilePointer() {
  131.         return pointer;
  132.     }
  133.     /**
  134.      * Sets the file-pointer offset, measured from the beginning of this 
  135.      * file, at which the next read occurs.
  136.      *
  137.      * @param      pos   the offset position, measured in bytes from the 
  138.      *                   beginning of the file, at which to set the file 
  139.      *                   pointer.
  140.      * @exception  IOException  if <code>pos</code> is less than 
  141.      *                          <code>0</code> or if an I/O error occurs.
  142.      */
  143.     public void seek(long pos) throws IOException {
  144.         if (pos < 0) {
  145.             throw new IOException(JaiI18N.getString("FileCacheSeekableStream0"));
  146.         }
  147.         pointer = pos;
  148.     }
  149.     /**
  150.      * Reads the next byte of data from the input stream. The value byte is
  151.      * returned as an <code>int</code> in the range <code>0</code> to
  152.      * <code>255</code>. If no byte is available because the end of the stream
  153.      * has been reached, the value <code>-1</code> is returned. This method
  154.      * blocks until input data is available, the end of the stream is detected,
  155.      * or an exception is thrown.
  156.      *
  157.      * @return     the next byte of data, or <code>-1</code> if the end of the
  158.      *             stream is reached.
  159.      * @exception  IOException  if an I/O error occurs.
  160.      */
  161.     public int read() throws IOException {
  162.         long next = pointer + 1;
  163.         long pos = readUntil(next);
  164.         if (pos >= next) {
  165.             cache.seek(pointer++);
  166.             return cache.read();
  167.         } else {
  168.             return -1;
  169.         }
  170.     }
  171.     /**
  172.      * Reads up to <code>len</code> bytes of data from the input stream into
  173.      * an array of bytes.  An attempt is made to read as many as
  174.      * <code>len</code> bytes, but a smaller number may be read, possibly
  175.      * zero. The number of bytes actually read is returned as an integer.
  176.      *
  177.      * <p> This method blocks until input data is available, end of file is
  178.      * detected, or an exception is thrown.
  179.      *
  180.      * <p> If <code>b</code> is <code>null</code>, a
  181.      * <code>NullPointerException</code> is thrown.
  182.      *
  183.      * <p> If <code>off</code> is negative, or <code>len</code> is negative, or
  184.      * <code>off+len</code> is greater than the length of the array
  185.      * <code>b</code>, then an <code>IndexOutOfBoundsException</code> is
  186.      * thrown.
  187.      *
  188.      * <p> If <code>len</code> is zero, then no bytes are read and
  189.      * <code>0</code> is returned; otherwise, there is an attempt to read at
  190.      * least one byte. If no byte is available because the stream is at end of
  191.      * file, the value <code>-1</code> is returned; otherwise, at least one
  192.      * byte is read and stored into <code>b</code>.
  193.      *
  194.      * <p> The first byte read is stored into element <code>b[off]</code>, the
  195.      * next one into <code>b[off+1]</code>, and so on. The number of bytes read
  196.      * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
  197.      * bytes actually read; these bytes will be stored in elements
  198.      * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
  199.      * leaving elements <code>b[off+</code><i>k</i><code>]</code> through
  200.      * <code>b[off+len-1]</code> unaffected.
  201.      *
  202.      * <p> In every case, elements <code>b[0]</code> through
  203.      * <code>b[off]</code> and elements <code>b[off+len]</code> through
  204.      * <code>b[b.length-1]</code> are unaffected.
  205.      *
  206.      * <p> If the first byte cannot be read for any reason other than end of
  207.      * file, then an <code>IOException</code> is thrown. In particular, an
  208.      * <code>IOException</code> is thrown if the input stream has been closed.
  209.      *
  210.      * @param      b     the buffer into which the data is read.
  211.      * @param      off   the start offset in array <code>b</code>
  212.      *                   at which the data is written.
  213.      * @param      len   the maximum number of bytes to read.
  214.      * @return     the total number of bytes read into the buffer, or
  215.      *             <code>-1</code> if there is no more data because the end of
  216.      *             the stream has been reached.
  217.      * @exception  IOException  if an I/O error occurs.
  218.      */
  219.     public int read(byte[] b, int off, int len) throws IOException {
  220.         if (b == null) {
  221.             throw new NullPointerException();
  222.         }
  223.         if ((off < 0) || (len < 0) || (off + len > b.length)) {
  224.             throw new IndexOutOfBoundsException();
  225.         }
  226.         if (len == 0) {
  227.             return 0;
  228.         }
  229.         long pos = readUntil(pointer + len);
  230.         // len will always fit into an int so this is safe
  231.         len = (int)Math.min((long)len, pos - pointer);
  232.         if (len > 0) {
  233.             cache.seek(pointer);
  234.             cache.readFully(b, off, len);
  235.             pointer += len;
  236.             return len;
  237.         } else {
  238.             return -1;
  239.         }
  240.     }
  241.     
  242.     /**
  243.      * Closes this stream and releases any system resources
  244.      * associated with the stream.
  245.      *
  246.      * @throws IOException if an I/O error occurs.
  247.      */
  248.     public void close() throws IOException {
  249.         super.close();
  250.         cache.close();
  251.         cacheFile.delete();
  252.     }
  253. }