< prev index next >

src/java.desktop/share/classes/javax/imageio/stream/FileCacheImageOutputStream.java

Print this page




  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.imageio.stream;
  27 
  28 import java.io.File;
  29 import java.io.IOException;
  30 import java.io.OutputStream;
  31 import java.io.RandomAccessFile;
  32 import java.nio.file.Files;
  33 import com.sun.imageio.stream.StreamCloser;
  34 
  35 /**
  36  * An implementation of <code>ImageOutputStream</code> that writes its
  37  * output to a regular <code>OutputStream</code>.  A file is used to
  38  * cache data until it is flushed to the output stream.
  39  *
  40  */
  41 public class FileCacheImageOutputStream extends ImageOutputStreamImpl {
  42 
  43     private OutputStream stream;
  44 
  45     private File cacheFile;
  46 
  47     private RandomAccessFile cache;
  48 
  49     // Pos after last (rightmost) byte written
  50     private long maxStreamPos = 0L;
  51 
  52     /** The CloseAction that closes the stream in
  53      *  the StreamCloser's shutdown hook                     */
  54     private final StreamCloser.CloseAction closeAction;
  55 
  56     /**
  57      * Constructs a <code>FileCacheImageOutputStream</code> that will write
  58      * to a given <code>outputStream</code>.
  59      *
  60      * <p> A temporary file is used as a cache.  If
  61      * <code>cacheDir</code>is non-<code>null</code> and is a
  62      * directory, the file will be created there.  If it is
  63      * <code>null</code>, the system-dependent default temporary-file
  64      * directory will be used (see the documentation for
  65      * <code>File.createTempFile</code> for details).
  66      *
  67      * @param stream an <code>OutputStream</code> to write to.
  68      * @param cacheDir a <code>File</code> indicating where the
  69      * cache file should be created, or <code>null</code> to use the
  70      * system directory.
  71      *
  72      * @exception IllegalArgumentException if <code>stream</code>
  73      * is <code>null</code>.
  74      * @exception IllegalArgumentException if <code>cacheDir</code> is
  75      * non-<code>null</code> but is not a directory.
  76      * @exception IOException if a cache file cannot be created.
  77      */
  78     public FileCacheImageOutputStream(OutputStream stream, File cacheDir)
  79         throws IOException {
  80         if (stream == null) {
  81             throw new IllegalArgumentException("stream == null!");
  82         }
  83         if ((cacheDir != null) && !(cacheDir.isDirectory())) {
  84             throw new IllegalArgumentException("Not a directory!");
  85         }
  86         this.stream = stream;
  87         if (cacheDir == null)
  88             this.cacheFile = Files.createTempFile("imageio", ".tmp").toFile();
  89         else
  90             this.cacheFile = Files.createTempFile(cacheDir.toPath(), "imageio", ".tmp")
  91                                   .toFile();
  92         this.cache = new RandomAccessFile(cacheFile, "rw");
  93 
  94         this.closeAction = StreamCloser.createCloseAction(this);
  95         StreamCloser.addToQueue(closeAction);


 138 
 139     public void write(byte[] b, int off, int len) throws IOException {
 140         flushBits(); // this will call checkClosed() for us
 141         cache.write(b, off, len);
 142         streamPos += len;
 143         maxStreamPos = Math.max(maxStreamPos, streamPos);
 144     }
 145 
 146     public long length() {
 147         try {
 148             checkClosed();
 149             return cache.length();
 150         } catch (IOException e) {
 151             return -1L;
 152         }
 153     }
 154 
 155     /**
 156      * Sets the current stream position and resets the bit offset to
 157      * 0.  It is legal to seek past the end of the file; an
 158      * <code>EOFException</code> will be thrown only if a read is
 159      * performed.  The file length will not be increased until a write
 160      * is performed.
 161      *
 162      * @exception IndexOutOfBoundsException if <code>pos</code> is smaller
 163      * than the flushed position.
 164      * @exception IOException if any other I/O error occurs.
 165      */
 166     public void seek(long pos) throws IOException {
 167         checkClosed();
 168 
 169         if (pos < flushedPos) {
 170             throw new IndexOutOfBoundsException();
 171         }
 172 
 173         cache.seek(pos);
 174         this.streamPos = cache.getFilePointer();
 175         maxStreamPos = Math.max(maxStreamPos, streamPos);
 176         this.bitOffset = 0;
 177     }
 178 
 179     /**
 180      * Returns <code>true</code> since this
 181      * <code>ImageOutputStream</code> caches data in order to allow
 182      * seeking backwards.
 183      *
 184      * @return <code>true</code>.
 185      *
 186      * @see #isCachedMemory
 187      * @see #isCachedFile
 188      */
 189     public boolean isCached() {
 190         return true;
 191     }
 192 
 193     /**
 194      * Returns <code>true</code> since this
 195      * <code>ImageOutputStream</code> maintains a file cache.
 196      *
 197      * @return <code>true</code>.
 198      *
 199      * @see #isCached
 200      * @see #isCachedMemory
 201      */
 202     public boolean isCachedFile() {
 203         return true;
 204     }
 205 
 206     /**
 207      * Returns <code>false</code> since this
 208      * <code>ImageOutputStream</code> does not maintain a main memory
 209      * cache.
 210      *
 211      * @return <code>false</code>.
 212      *
 213      * @see #isCached
 214      * @see #isCachedFile
 215      */
 216     public boolean isCachedMemory() {
 217         return false;
 218     }
 219 
 220     /**
 221      * Closes this <code>FileCacheImageOutputStream</code>.  All
 222      * pending data is flushed to the output, and the cache file
 223      * is closed and removed.  The destination <code>OutputStream</code>
 224      * is not closed.
 225      *
 226      * @exception IOException if an error occurs.
 227      */
 228     public void close() throws IOException {
 229         maxStreamPos = cache.length();
 230 
 231         seek(maxStreamPos);
 232         flushBefore(maxStreamPos);
 233         super.close();
 234         cache.close();
 235         cache = null;
 236         cacheFile.delete();
 237         cacheFile = null;
 238         stream.flush();
 239         stream = null;
 240         StreamCloser.removeFromQueue(closeAction);
 241     }
 242 
 243     public void flushBefore(long pos) throws IOException {


  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.imageio.stream;
  27 
  28 import java.io.File;
  29 import java.io.IOException;
  30 import java.io.OutputStream;
  31 import java.io.RandomAccessFile;
  32 import java.nio.file.Files;
  33 import com.sun.imageio.stream.StreamCloser;
  34 
  35 /**
  36  * An implementation of {@code ImageOutputStream} that writes its
  37  * output to a regular {@code OutputStream}.  A file is used to
  38  * cache data until it is flushed to the output stream.
  39  *
  40  */
  41 public class FileCacheImageOutputStream extends ImageOutputStreamImpl {
  42 
  43     private OutputStream stream;
  44 
  45     private File cacheFile;
  46 
  47     private RandomAccessFile cache;
  48 
  49     // Pos after last (rightmost) byte written
  50     private long maxStreamPos = 0L;
  51 
  52     /** The CloseAction that closes the stream in
  53      *  the StreamCloser's shutdown hook                     */
  54     private final StreamCloser.CloseAction closeAction;
  55 
  56     /**
  57      * Constructs a {@code FileCacheImageOutputStream} that will write
  58      * to a given {@code outputStream}.
  59      *
  60      * <p> A temporary file is used as a cache.  If
  61      * {@code cacheDir} is non-{@code null} and is a
  62      * directory, the file will be created there.  If it is
  63      * {@code null}, the system-dependent default temporary-file
  64      * directory will be used (see the documentation for
  65      * {@code File.createTempFile} for details).
  66      *
  67      * @param stream an {@code OutputStream} to write to.
  68      * @param cacheDir a {@code File} indicating where the
  69      * cache file should be created, or {@code null} to use the
  70      * system directory.
  71      *
  72      * @exception IllegalArgumentException if {@code stream}
  73      * is {@code null}.
  74      * @exception IllegalArgumentException if {@code cacheDir} is
  75      * non-{@code null} but is not a directory.
  76      * @exception IOException if a cache file cannot be created.
  77      */
  78     public FileCacheImageOutputStream(OutputStream stream, File cacheDir)
  79         throws IOException {
  80         if (stream == null) {
  81             throw new IllegalArgumentException("stream == null!");
  82         }
  83         if ((cacheDir != null) && !(cacheDir.isDirectory())) {
  84             throw new IllegalArgumentException("Not a directory!");
  85         }
  86         this.stream = stream;
  87         if (cacheDir == null)
  88             this.cacheFile = Files.createTempFile("imageio", ".tmp").toFile();
  89         else
  90             this.cacheFile = Files.createTempFile(cacheDir.toPath(), "imageio", ".tmp")
  91                                   .toFile();
  92         this.cache = new RandomAccessFile(cacheFile, "rw");
  93 
  94         this.closeAction = StreamCloser.createCloseAction(this);
  95         StreamCloser.addToQueue(closeAction);


 138 
 139     public void write(byte[] b, int off, int len) throws IOException {
 140         flushBits(); // this will call checkClosed() for us
 141         cache.write(b, off, len);
 142         streamPos += len;
 143         maxStreamPos = Math.max(maxStreamPos, streamPos);
 144     }
 145 
 146     public long length() {
 147         try {
 148             checkClosed();
 149             return cache.length();
 150         } catch (IOException e) {
 151             return -1L;
 152         }
 153     }
 154 
 155     /**
 156      * Sets the current stream position and resets the bit offset to
 157      * 0.  It is legal to seek past the end of the file; an
 158      * {@code EOFException} will be thrown only if a read is
 159      * performed.  The file length will not be increased until a write
 160      * is performed.
 161      *
 162      * @exception IndexOutOfBoundsException if {@code pos} is smaller
 163      * than the flushed position.
 164      * @exception IOException if any other I/O error occurs.
 165      */
 166     public void seek(long pos) throws IOException {
 167         checkClosed();
 168 
 169         if (pos < flushedPos) {
 170             throw new IndexOutOfBoundsException();
 171         }
 172 
 173         cache.seek(pos);
 174         this.streamPos = cache.getFilePointer();
 175         maxStreamPos = Math.max(maxStreamPos, streamPos);
 176         this.bitOffset = 0;
 177     }
 178 
 179     /**
 180      * Returns {@code true} since this
 181      * {@code ImageOutputStream} caches data in order to allow
 182      * seeking backwards.
 183      *
 184      * @return {@code true}.
 185      *
 186      * @see #isCachedMemory
 187      * @see #isCachedFile
 188      */
 189     public boolean isCached() {
 190         return true;
 191     }
 192 
 193     /**
 194      * Returns {@code true} since this
 195      * {@code ImageOutputStream} maintains a file cache.
 196      *
 197      * @return {@code true}.
 198      *
 199      * @see #isCached
 200      * @see #isCachedMemory
 201      */
 202     public boolean isCachedFile() {
 203         return true;
 204     }
 205 
 206     /**
 207      * Returns {@code false} since this
 208      * {@code ImageOutputStream} does not maintain a main memory
 209      * cache.
 210      *
 211      * @return {@code false}.
 212      *
 213      * @see #isCached
 214      * @see #isCachedFile
 215      */
 216     public boolean isCachedMemory() {
 217         return false;
 218     }
 219 
 220     /**
 221      * Closes this {@code FileCacheImageOutputStream}.  All
 222      * pending data is flushed to the output, and the cache file
 223      * is closed and removed.  The destination {@code OutputStream}
 224      * is not closed.
 225      *
 226      * @exception IOException if an error occurs.
 227      */
 228     public void close() throws IOException {
 229         maxStreamPos = cache.length();
 230 
 231         seek(maxStreamPos);
 232         flushBefore(maxStreamPos);
 233         super.close();
 234         cache.close();
 235         cache = null;
 236         cacheFile.delete();
 237         cacheFile = null;
 238         stream.flush();
 239         stream = null;
 240         StreamCloser.removeFromQueue(closeAction);
 241     }
 242 
 243     public void flushBefore(long pos) throws IOException {
< prev index next >