KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * @(#)FileCacheImageOutputStream.java 1.24 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.FileNotFoundException JavaDoc;
13 import java.io.IOException JavaDoc;
14 import java.io.OutputStream JavaDoc;
15 import java.io.RandomAccessFile JavaDoc;
16 import com.sun.imageio.stream.StreamCloser;
17
18 /**
19  * An implementation of <code>ImageOutputStream</code> that writes its
20  * output to a regular <code>OutputStream</code>. A file is used to
21  * cache data until it is flushed to the output stream.
22  *
23  * @version 0.5
24  */

25 public class FileCacheImageOutputStream extends ImageOutputStreamImpl JavaDoc {
26
27     private OutputStream JavaDoc stream;
28
29     private File JavaDoc cacheFile;
30
31     private RandomAccessFile JavaDoc cache;
32     
33     // Pos after last (rightmost) byte written
34
private long maxStreamPos = 0L;
35
36     /**
37      * Constructs a <code>FileCacheImageOutputStream</code> that will write
38      * to a given <code>outputStream</code>.
39      *
40      * <p> A temporary file is used as a cache. If
41      * <code>cacheDir</code>is non-<code>null</code> and is a
42      * directory, the file will be created there. If it is
43      * <code>null</code>, the system-dependent default temporary-file
44      * directory will be used (see the documentation for
45      * <code>File.createTempFile</code> for details).
46      *
47      * @param stream an <code>OutputStream</code> to write to.
48      * @param cacheDir a <code>File</code> indicating where the
49      * cache file should be created, or <code>null</code> to use the
50      * system directory.
51      *
52      * @exception IllegalArgumentException if <code>stream</code>
53      * is <code>null</code>.
54      * @exception IllegalArgumentException if <code>cacheDir</code> is
55      * non-<code>null</code> but is not a directory.
56      * @exception IOException if a cache file cannot be created.
57      */

58     public FileCacheImageOutputStream(OutputStream JavaDoc stream, File JavaDoc cacheDir)
59         throws IOException JavaDoc {
60         if (stream == null) {
61             throw new IllegalArgumentException JavaDoc("stream == null!");
62         }
63         if ((cacheDir != null) && !(cacheDir.isDirectory())) {
64             throw new IllegalArgumentException JavaDoc("Not a directory!");
65         }
66         this.stream = stream;
67         this.cacheFile =
68             File.createTempFile("imageio", ".tmp", cacheDir);
69         this.cache = new RandomAccessFile JavaDoc(cacheFile, "rw");
70     StreamCloser.addToQueue(this);
71     }
72
73     public int read() throws IOException JavaDoc {
74         bitOffset = 0;
75         int val = cache.read();
76         if (val != -1) {
77             ++streamPos;
78         }
79         return val;
80     }
81
82     public int read(byte[] b, int off, int len) throws IOException JavaDoc {
83         bitOffset = 0;
84         int nbytes = cache.read(b, off, len);
85         if (nbytes != -1) {
86             streamPos += nbytes;
87         }
88         return nbytes;
89     }
90
91     public void write(int b) throws IOException JavaDoc {
92         flushBits();
93         cache.write(b);
94         ++streamPos;
95         maxStreamPos = Math.max(maxStreamPos, streamPos);
96     }
97
98     public void write(byte[] b, int off, int len) throws IOException JavaDoc {
99         flushBits();
100         cache.write(b, off, len);
101         streamPos += len;
102         maxStreamPos = Math.max(maxStreamPos, streamPos);
103     }
104
105     public long length() {
106         try {
107             return cache.length();
108         } catch (IOException JavaDoc e) {
109             return -1L;
110         }
111     }
112
113     /**
114      * Sets the current stream position and resets the bit offset to
115      * 0. It is legal to seek past the end of the file; an
116      * <code>EOFException</code> will be thrown only if a read is
117      * performed. The file length will not be increased until a write
118      * is performed.
119      *
120      * @exception IndexOutOfBoundsException if <code>pos</code> is smaller
121      * than the flushed position.
122      * @exception IOException if any other I/O error occurs.
123      */

124     public void seek(long pos) throws IOException JavaDoc {
125         checkClosed();
126
127         if (pos < flushedPos) {
128             throw new IndexOutOfBoundsException JavaDoc();
129         }
130
131         cache.seek(pos);
132         this.streamPos = cache.getFilePointer();
133         maxStreamPos = Math.max(maxStreamPos, streamPos);
134         this.bitOffset = 0;
135     }
136
137     /**
138      * Returns <code>true</code> since this
139      * <code>ImageOutputStream</code> caches data in order to allow
140      * seeking backwards.
141      *
142      * @return <code>true</code>.
143      *
144      * @see #isCachedMemory
145      * @see #isCachedFile
146      */

147     public boolean isCached() {
148         return true;
149     }
150
151     /**
152      * Returns <code>true</code> since this
153      * <code>ImageOutputStream</code> maintains a file cache.
154      *
155      * @return <code>true</code>.
156      *
157      * @see #isCached
158      * @see #isCachedMemory
159      */

160     public boolean isCachedFile() {
161         return true;
162     }
163
164     /**
165      * Returns <code>false</code> since this
166      * <code>ImageOutputStream</code> does not maintain a main memory
167      * cache.
168      *
169      * @return <code>false</code>.
170      *
171      * @see #isCached
172      * @see #isCachedFile
173      */

174     public boolean isCachedMemory() {
175         return false;
176     }
177
178     /**
179      * Closes this <code>FileCacheImageOututStream</code>. All
180      * pending data is flushed to the output, and the cache file
181      * is closed and removed. The destination <code>OutputStream</code>
182      * is not closed.
183      *
184      * @exception IOException if an error occurs.
185      */

186     public void close() throws IOException JavaDoc {
187         maxStreamPos = cache.length();
188
189         seek(maxStreamPos);
190         flushBefore(maxStreamPos);
191         super.close();
192         cache.close();
193         cacheFile.delete();
194         stream.flush();
195         stream = null;
196     StreamCloser.removeFromQueue(this);
197     }
198
199     public void flushBefore(long pos) throws IOException JavaDoc {
200         long oFlushedPos = flushedPos;
201         super.flushBefore(pos);
202
203         long flushBytes = flushedPos - oFlushedPos;
204         if (flushBytes > 0) {
205             int bufLen = 512;
206             byte[] buf = new byte[bufLen];
207             cache.seek(oFlushedPos);
208             while (flushBytes > 0) {
209                 int len = (int)Math.min(flushBytes, bufLen);
210                 cache.readFully(buf, 0, len);
211                 stream.write(buf, 0, len);
212                 flushBytes -= len;
213             }
214             stream.flush();
215         }
216     }
217 }
218
Popular Tags