KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > imageio > stream > FileCacheImageInputStream


1 /*
2  * @(#)FileCacheImageInputStream.java 1.29 05/08/17
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.imageio.stream;
9
10 import java.io.DataInput JavaDoc;
11 import java.io.File JavaDoc;
12 import java.io.InputStream JavaDoc;
13 import java.io.IOException JavaDoc;
14 import java.io.RandomAccessFile JavaDoc;
15 import com.sun.imageio.stream.StreamCloser;
16
17 /**
18  * An implementation of <code>ImageInputStream</code> that gets its
19  * input from a regular <code>InputStream</code>. A file is used to
20  * cache previously read data.
21  *
22  * @version 0.5
23  */

24 public class FileCacheImageInputStream extends ImageInputStreamImpl JavaDoc {
25
26     private InputStream JavaDoc stream;
27
28     private File JavaDoc cacheFile;
29
30     private RandomAccessFile JavaDoc cache;
31
32     private static final int BUFFER_LENGTH = 1024;
33
34     private byte[] buf = new byte[BUFFER_LENGTH];
35
36     private long length = 0L;
37
38     private boolean foundEOF = false;
39
40     /**
41      * Constructs a <code>FileCacheImageInputStream</code> that will read
42      * from a given <code>InputStream</code>.
43      *
44      * <p> A temporary file is used as a cache. If
45      * <code>cacheDir</code>is non-<code>null</code> and is a
46      * directory, the file will be created there. If it is
47      * <code>null</code>, the system-dependent default temporary-file
48      * directory will be used (see the documentation for
49      * <code>File.createTempFile</code> for details).
50      *
51      * @param stream an <code>InputStream</code> to read from.
52      * @param cacheDir a <code>File</code> indicating where the
53      * cache file should be created, or <code>null</code> to use the
54      * system directory.
55      *
56      * @exception IllegalArgumentException if <code>stream</code> is
57      * <code>null</code>.
58      * @exception IllegalArgumentException if <code>cacheDir</code> is
59      * non-<code>null</code> but is not a directory.
60      * @exception IOException if a cache file cannot be created.
61      */

62     public FileCacheImageInputStream(InputStream JavaDoc stream, File JavaDoc cacheDir)
63         throws IOException JavaDoc {
64         if (stream == null) {
65             throw new IllegalArgumentException JavaDoc("stream == null!");
66         }
67         if ((cacheDir != null) && !(cacheDir.isDirectory())) {
68             throw new IllegalArgumentException JavaDoc("Not a directory!");
69         }
70         this.stream = stream;
71         this.cacheFile =
72             File.createTempFile("imageio", ".tmp", cacheDir);
73         this.cache = new RandomAccessFile JavaDoc(cacheFile, "rw");
74     StreamCloser.addToQueue(this);
75     }
76
77     /**
78      * Ensures that at least <code>pos</code> bytes are cached,
79      * or the end of the source is reached. The return value
80      * is equal to the smaller of <code>pos</code> and the
81      * length of the source file.
82      */

83     private long readUntil(long pos) throws IOException JavaDoc {
84         // We've already got enough data cached
85
if (pos < length) {
86             return pos;
87         }
88         // pos >= length but length isn't getting any bigger, so return it
89
if (foundEOF) {
90             return length;
91         }
92
93         long len = pos - length;
94         cache.seek(length);
95         while (len > 0) {
96             // Copy a buffer's worth of data from the source to the cache
97
// BUFFER_LENGTH will always fit into an int so this is safe
98
int nbytes =
99                 stream.read(buf, 0, (int)Math.min(len, (long)BUFFER_LENGTH));
100             if (nbytes == -1) {
101                 foundEOF = true;
102                 return length;
103             }
104
105             cache.write(buf, 0, nbytes);
106             len -= nbytes;
107             length += nbytes;
108         }
109
110         return pos;
111     }
112
113     public int read() throws IOException JavaDoc {
114         bitOffset = 0;
115         long next = streamPos + 1;
116         long pos = readUntil(next);
117         if (pos >= next) {
118             cache.seek(streamPos++);
119             return cache.read();
120         } else {
121             return -1;
122         }
123     }
124
125     public int read(byte[] b, int off, int len) throws IOException JavaDoc {
126         if (b == null) {
127             throw new NullPointerException JavaDoc();
128         }
129         // Fix 4430357 - if off + len < 0, overflow occurred
130
if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
131             throw new IndexOutOfBoundsException JavaDoc();
132         }
133         if (len == 0) {
134             return 0;
135         }
136
137         checkClosed();
138
139         bitOffset = 0;
140
141         long pos = readUntil(streamPos + len);
142
143         // len will always fit into an int so this is safe
144
len = (int)Math.min((long)len, pos - streamPos);
145         if (len > 0) {
146             cache.seek(streamPos);
147             cache.readFully(b, off, len);
148             streamPos += len;
149             return len;
150         } else {
151             return -1;
152         }
153     }
154
155     /**
156      * Returns <code>true</code> since this
157      * <code>ImageInputStream</code> caches data in order to allow
158      * seeking backwards.
159      *
160      * @return <code>true</code>.
161      *
162      * @see #isCachedMemory
163      * @see #isCachedFile
164      */

165     public boolean isCached() {
166         return true;
167     }
168
169     /**
170      * Returns <code>true</code> since this
171      * <code>ImageInputStream</code> maintains a file cache.
172      *
173      * @return <code>true</code>.
174      *
175      * @see #isCached
176      * @see #isCachedMemory
177      */

178     public boolean isCachedFile() {
179         return true;
180     }
181
182     /**
183      * Returns <code>false</code> since this
184      * <code>ImageInputStream</code> does not maintain a main memory
185      * cache.
186      *
187      * @return <code>false</code>.
188      *
189      * @see #isCached
190      * @see #isCachedFile
191      */

192     public boolean isCachedMemory() {
193         return false;
194     }
195
196     /**
197      * Closes this <code>FileCacheImageInputStream</code>, closing
198      * and removing the cache file. The source <code>InputStream</code>
199      * is not closed.
200      *
201      * @exception IOException if an error occurs.
202      */

203     public void close() throws IOException JavaDoc {
204         super.close();
205         cache.close();
206         cacheFile.delete();
207         stream = null;
208     StreamCloser.removeFromQueue(this);
209     }
210 }
211
Popular Tags