001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package javax.imageio.stream;
019:
020: import java.io.IOException;
021: import java.io.File;
022: import java.io.OutputStream;
023: import java.io.RandomAccessFile;
024:
025: public class FileCacheImageOutputStream extends ImageOutputStreamImpl {
026: static final String IIO_TEMP_FILE_PREFIX = "iioCache";
027: static final int MAX_BUFFER_LEN = 1048575; // 1 MB - is it not too much?
028:
029: private OutputStream os;
030: private File file;
031: private RandomAccessFile raf;
032:
033: public FileCacheImageOutputStream(OutputStream stream, File cacheDir)
034: throws IOException {
035: if (stream == null) {
036: throw new IllegalArgumentException("stream == null!");
037: }
038: os = stream;
039:
040: if (cacheDir == null || cacheDir.isDirectory()) {
041: file = File.createTempFile(IIO_TEMP_FILE_PREFIX, null,
042: cacheDir);
043: file.deleteOnExit();
044: } else {
045: throw new IllegalArgumentException("Not a directory!");
046: }
047:
048: raf = new RandomAccessFile(file, "rw");
049: }
050:
051: @Override
052: public void close() throws IOException {
053: flushBefore(raf.length());
054: super .close();
055: raf.close();
056: file.delete();
057: }
058:
059: @Override
060: public boolean isCached() {
061: return true;
062: }
063:
064: @Override
065: public boolean isCachedFile() {
066: return true;
067: }
068:
069: @Override
070: public boolean isCachedMemory() {
071: return false;
072: }
073:
074: @Override
075: public void write(int b) throws IOException {
076: flushBits(); // See the flushBits method description
077:
078: raf.write(b);
079: streamPos++;
080: }
081:
082: @Override
083: public void write(byte[] b, int off, int len) throws IOException {
084: flushBits(); // See the flushBits method description
085:
086: raf.write(b, off, len);
087: streamPos += len;
088: }
089:
090: @Override
091: public int read() throws IOException {
092: bitOffset = 0; // Should reset
093:
094: int res = raf.read();
095: if (res >= 0) {
096: streamPos++;
097: }
098:
099: return res;
100: }
101:
102: @Override
103: public int read(byte[] b, int off, int len) throws IOException {
104: bitOffset = 0;
105:
106: int numRead = raf.read(b, off, len);
107: if (numRead > 0) {
108: streamPos += numRead;
109: }
110:
111: return numRead;
112: }
113:
114: @Override
115: public void flushBefore(long pos) throws IOException {
116: long readFromPos = flushedPos;
117: super .flushBefore(pos);
118:
119: long bytesToRead = pos - readFromPos;
120: raf.seek(readFromPos);
121:
122: if (bytesToRead < MAX_BUFFER_LEN) {
123: byte buffer[] = new byte[(int) bytesToRead];
124: raf.readFully(buffer);
125: os.write(buffer);
126: } else {
127: byte buffer[] = new byte[MAX_BUFFER_LEN];
128: while (bytesToRead > 0) {
129: int count = (int) Math.min(MAX_BUFFER_LEN, bytesToRead);
130: raf.readFully(buffer, 0, count);
131: os.write(buffer, 0, count);
132: bytesToRead -= count;
133: }
134: }
135:
136: os.flush();
137:
138: if (pos != streamPos) {
139: raf.seek(streamPos); // Reset the position
140: }
141: }
142:
143: @Override
144: public void seek(long pos) throws IOException {
145: if (pos < flushedPos) {
146: throw new IndexOutOfBoundsException();
147: }
148:
149: raf.seek(pos);
150: streamPos = raf.getFilePointer();
151: bitOffset = 0;
152: }
153:
154: @Override
155: public long length() {
156: try {
157: return raf.length();
158: } catch (IOException e) {
159: return -1L;
160: }
161: }
162: }
|