FileDocCategorySizeDatePackage
FileCacheImageInputStream.javaAPI DocJava SE 6 API8183Tue Jun 10 00:26:08 BST 2008javax.imageio.stream

FileCacheImageInputStream

public class FileCacheImageInputStream extends ImageInputStreamImpl
An implementation of ImageInputStream that gets its input from a regular InputStream. A file is used to cache previously read data.
version
0.5

Fields Summary
private InputStream
stream
private File
cacheFile
private RandomAccessFile
cache
private static final int
BUFFER_LENGTH
private byte[]
buf
private long
length
private boolean
foundEOF
private final Object
disposerReferent
The referent to be registered with the Disposer.
private final DisposerRecord
disposerRecord
The DisposerRecord that closes the underlying cache.
Constructors Summary
public FileCacheImageInputStream(InputStream stream, File cacheDir)
Constructs a FileCacheImageInputStream that will read from a given InputStream.

A temporary file is used as a cache. If cacheDiris non-null and is a directory, the file will be created there. If it is null, the system-dependent default temporary-file directory will be used (see the documentation for File.createTempFile for details).

param
stream an InputStream to read from.
param
cacheDir a File indicating where the cache file should be created, or null to use the system directory.
exception
IllegalArgumentException if stream is null.
exception
IllegalArgumentException if cacheDir is non-null but is not a directory.
exception
IOException if a cache file cannot be created.


                                                                                                                   
        
          
        if (stream == null) {
            throw new IllegalArgumentException("stream == null!");
        }
        if ((cacheDir != null) && !(cacheDir.isDirectory())) {
            throw new IllegalArgumentException("Not a directory!");
        }
        this.stream = stream;
        this.cacheFile =
            File.createTempFile("imageio", ".tmp", cacheDir);
        this.cache = new RandomAccessFile(cacheFile, "rw");
        StreamCloser.addToQueue(this);

        disposerRecord = new StreamDisposerRecord(cacheFile, cache);
        if (getClass() == FileCacheImageInputStream.class) {
            disposerReferent = new Object();
            Disposer.addRecord(disposerReferent, disposerRecord);
        } else {
            disposerReferent = new StreamFinalizer(this);
        }
    
Methods Summary
public voidclose()
Closes this FileCacheImageInputStream, closing and removing the cache file. The source InputStream is not closed.

exception
IOException if an error occurs.

        super.close();
        disposerRecord.dispose(); // this will close/delete the cache file
        stream = null;
        cache = null;
        cacheFile = null;
        StreamCloser.removeFromQueue(this);
    
protected voidfinalize()
{@inheritDoc}

        // Empty finalizer: for performance reasons we instead use the
        // Disposer mechanism for ensuring that the underlying
        // RandomAccessFile is closed/deleted prior to garbage collection
    
public booleanisCached()
Returns true since this ImageInputStream caches data in order to allow seeking backwards.

return
true.
see
#isCachedMemory
see
#isCachedFile

        return true;
    
public booleanisCachedFile()
Returns true since this ImageInputStream maintains a file cache.

return
true.
see
#isCached
see
#isCachedMemory

        return true;
    
public booleanisCachedMemory()
Returns false since this ImageInputStream does not maintain a main memory cache.

return
false.
see
#isCached
see
#isCachedFile

        return false;
    
public intread()

        checkClosed();
        bitOffset = 0;
        long next = streamPos + 1;
        long pos = readUntil(next);
        if (pos >= next) {
            cache.seek(streamPos++);
            return cache.read();
        } else {
            return -1;
        }
    
public intread(byte[] b, int off, int len)

        checkClosed();

        if (b == null) {
            throw new NullPointerException("b == null!");
        }
        // Fix 4430357 - if off + len < 0, overflow occurred
        if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
            throw new IndexOutOfBoundsException
                ("off < 0 || len < 0 || off+len > b.length || off+len < 0!");
        }

        bitOffset = 0;

        if (len == 0) {
            return 0;
        }

        long pos = readUntil(streamPos + len);

        // len will always fit into an int so this is safe
        len = (int)Math.min((long)len, pos - streamPos);
        if (len > 0) {
            cache.seek(streamPos);
            cache.readFully(b, off, len);
            streamPos += len;
            return len;
        } else {
            return -1;
        }
    
private longreadUntil(long pos)
Ensures that at least pos bytes are cached, or the end of the source is reached. The return value is equal to the smaller of pos and the length of the source file.

        // We've already got enough data cached
        if (pos < length) {
            return pos;
        }
        // pos >= length but length isn't getting any bigger, so return it
        if (foundEOF) {
            return length;
        }

        long len = pos - length;
        cache.seek(length);
        while (len > 0) {
            // Copy a buffer's worth of data from the source to the cache
            // BUFFER_LENGTH will always fit into an int so this is safe
            int nbytes =
                stream.read(buf, 0, (int)Math.min(len, (long)BUFFER_LENGTH));
            if (nbytes == -1) {
                foundEOF = true;
                return length;
            }

            cache.write(buf, 0, nbytes);
            len -= nbytes;
            length += nbytes;
        }

        return pos;