KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > izforge > izpack > io > FileSpanningOutputStream


1 /*
2  * IzPack - Copyright 2001-2007 Julien Ponge, All Rights Reserved.
3  *
4  * http://www.izforge.com/izpack/ http://developer.berlios.de/projects/izpack/
5  *
6  * Copyright 2007 Dennis Reil
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
9  * in compliance with the License. You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software distributed under the License
14  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
15  * or implied. See the License for the specific language governing permissions and limitations under
16  * the License.
17  */

18 package com.izforge.izpack.io;
19
20 import java.io.File JavaDoc;
21 import java.io.FileOutputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.OutputStream JavaDoc;
24 import java.util.zip.GZIPOutputStream JavaDoc;
25
26 import com.izforge.izpack.util.Debug;
27
28 /**
29  * An outputstream which transparently spans over multiple volumes. The size of the volumes and an
30  * additonal space for the first volume can be specified.
31  *
32  * @author Dennis Reil, <Dennis.Reil@reddot.de>
33  */

34 public class FileSpanningOutputStream extends OutputStream JavaDoc
35 {
36
37     public static final long KB = 1024;
38
39     public static final long MB = 1024 * KB;
40
41     // the default size of a volume
42
public static final long DEFAULT_VOLUME_SIZE = 650 * MB;
43
44     // free space on first volume
45
// may be used for placing additional files on cd beside the pack files
46
// default is 0, so there's no additional space
47
public static final long DEFAULT_ADDITIONAL_FIRST_VOLUME_FREE_SPACE_SIZE = 0;
48
49     // the default volume name
50
protected static final String JavaDoc DEFAULT_VOLUME_NAME = "installer";
51
52     protected static final long FILE_NOT_AVAILABLE = -1;
53
54     // the maximum size of a volume
55
protected long maxvolumesize = DEFAULT_VOLUME_SIZE;
56
57     // the addition free space of volume 0
58
protected long firstvolumefreespacesize = DEFAULT_ADDITIONAL_FIRST_VOLUME_FREE_SPACE_SIZE;
59     
60     public static final String JavaDoc VOLUMES_INFO = "/volumes.info";
61
62     // the current file this stream writes to
63
protected File JavaDoc currentfile;
64
65     // the name of the volumes
66
protected String JavaDoc volumename;
67
68     // the current index of the volume, the stream writes to
69
protected int currentvolumeindex;
70
71     // a normal file outputstream for writting to the current volume
72
private FileOutputStream JavaDoc fileoutputstream;
73
74     private GZIPOutputStream JavaDoc zippedoutputstream;
75
76     // the current position in the open file
77
protected long filepointer;
78
79     protected long totalbytesofpreviousvolumes;
80
81     /**
82      * Creates a new spanning output stream with specified volume names and a maximum volume size
83      *
84      * @param volumename - the name of the volumes
85      * @param maxvolumesize - the maximum volume size
86      * @throws IOException
87      */

88     public FileSpanningOutputStream(String JavaDoc volumename, long maxvolumesize) throws IOException JavaDoc
89     {
90         this(new File JavaDoc(volumename), maxvolumesize);
91     }
92
93     /**
94      * Creates a new spanning output stream with specified volume names and a maximum volume size
95      *
96      * @param volume - the first volume
97      * @param maxvolumesize - the maximum volume size
98      * @throws IOException
99      */

100     public FileSpanningOutputStream(File JavaDoc volume, long maxvolumesize) throws IOException JavaDoc
101     {
102         this(volume, maxvolumesize, 0);
103     }
104
105     /**
106      * Creates a new spanning output stream with specified volume names and a maximum volume size
107      *
108      * @param volume - the first volume
109      * @param maxvolumesize - the maximum volume size
110      * @param currentvolume - the current volume
111      * @throws IOException
112      */

113     protected FileSpanningOutputStream(File JavaDoc volume, long maxvolumesize, int currentvolume)
114             throws IOException JavaDoc
115     {
116         this.createVolumeOutputStream(volume, maxvolumesize, currentvolume);
117     }
118
119     /**
120      * Actually creates the outputstream for writing a volume with index currentvolume and a maximum
121      * of maxvolumesize
122      *
123      * @param volume - the volume to write to
124      * @param maxvolumesize - the maximum volume size
125      * @param currentvolume - the currentvolume index
126      * @throws IOException
127      */

128     private void createVolumeOutputStream(File JavaDoc volume, long maxvolumesize, int currentvolume)
129             throws IOException JavaDoc
130     {
131         fileoutputstream = new FileOutputStream JavaDoc(volume);
132         zippedoutputstream = new GZIPOutputStream JavaDoc(fileoutputstream, 256);
133         currentfile = volume;
134         this.currentvolumeindex = currentvolume;
135         this.maxvolumesize = maxvolumesize;
136         // try to get the volumename from the given volume file
137
// the first volume has no suffix, additional volumes have a .INDEX# suffix
138
String JavaDoc volumesuffix = "." + currentvolume;
139         String JavaDoc volabsolutePath = volume.getAbsolutePath();
140         if (volabsolutePath.endsWith(volumesuffix))
141         {
142             volumename = volabsolutePath.substring(0, volabsolutePath.indexOf(volumesuffix));
143         }
144         else
145         {
146             volumename = volabsolutePath;
147         }
148     }
149
150     /**
151      *
152      * @param volume
153      * @throws IOException
154      */

155     public FileSpanningOutputStream(File JavaDoc volume) throws IOException JavaDoc
156     {
157         this(volume.getAbsolutePath(), DEFAULT_VOLUME_SIZE);
158     }
159
160     /**
161      *
162      * @param volumename
163      * @throws IOException
164      */

165     public FileSpanningOutputStream(String JavaDoc volumename) throws IOException JavaDoc
166     {
167         this(volumename, DEFAULT_VOLUME_SIZE);
168     }
169
170     /**
171      *
172      * @throws IOException
173      */

174     public FileSpanningOutputStream() throws IOException JavaDoc
175     {
176         this(DEFAULT_VOLUME_NAME, DEFAULT_VOLUME_SIZE);
177     }
178
179     /**
180      * Returns the size of the current volume
181      *
182      * @return the size of the current volume FILE_NOT_AVAILABLE, if there's no current volume
183      */

184     protected long getCurrentVolumeSize()
185     {
186         if (currentfile == null) { return FILE_NOT_AVAILABLE; }
187         try
188         {
189             flush();
190         }
191         catch (IOException JavaDoc e)
192         {
193             e.printStackTrace();
194         }
195         // create a new instance
196
currentfile = new File JavaDoc(currentfile.getAbsolutePath());
197         if (currentvolumeindex == 0)
198         {
199             // this is the first volume, add the additional free space
200
// and add a reserve for overhead and not yet written data
201
return currentfile.length() + this.firstvolumefreespacesize
202                     + Math.round(0.001 * currentfile.length());
203         }
204         else
205         {
206             // not the first volume, just return the actual length
207
// and add a reserve for overhead and not yet written data
208
return currentfile.length() + Math.round(0.001 * currentfile.length());
209         }
210     }
211
212     /**
213      * Closes the stream to the current volume and reopens to the next volume
214      *
215      * @throws IOException
216      */

217     protected void createStreamToNextVolume() throws IOException JavaDoc
218     {
219         // close current stream
220
close();
221         totalbytesofpreviousvolumes = currentfile.length();
222         currentvolumeindex++;
223         // get the name of the next volume
224
String JavaDoc nextvolumename = volumename + "." + currentvolumeindex;
225         // does the creation
226
this.createVolumeOutputStream(new File JavaDoc(nextvolumename), this.maxvolumesize,
227                 this.currentvolumeindex);
228     }
229
230     /**
231      * @see java.io.OutputStream#close()
232      */

233     public void close() throws IOException JavaDoc
234     {
235         this.flush();
236         zippedoutputstream.close();
237         fileoutputstream.close();
238         // reset the filepointer
239
// filepointer = 0;
240
}
241
242     /**
243      * @see java.io.OutputStream#write(byte[], int, int)
244      */

245     public void write(byte[] b, int off, int len) throws IOException JavaDoc
246     {
247         if (len > maxvolumesize) { throw new IOException JavaDoc(
248                 "file can't be written. buffer length exceeded maxvolumesize (" + " > "
249                         + maxvolumesize + ")"); }
250         // get the current size of this file
251
long currentsize = getCurrentVolumeSize();
252         // calculate the available bytes
253
long available = maxvolumesize - currentsize;
254
255         if (available < len)
256         {
257             Debug.trace("Not enough space left on volume. available: " + available);
258             Debug.trace("current size is: " + currentsize);
259             // there's not enough space available
260
// create the next volume
261
this.createStreamToNextVolume();
262         }
263         // enough space available, just write to the outputstream
264
zippedoutputstream.write(b, off, len);
265         // increase filepointer by written bytes
266
filepointer += len;
267     }
268
269     /**
270      * @see java.io.OutputStream#write(byte[])
271      */

272     public void write(byte[] b) throws IOException JavaDoc
273     {
274         this.write(b, 0, b.length);
275     }
276
277     /**
278      * @see java.io.OutputStream#write(int)
279      */

280     public void write(int b) throws IOException JavaDoc
281     {
282         long availablebytes = maxvolumesize - getCurrentVolumeSize();
283         if (availablebytes >= 1)
284         {
285             zippedoutputstream.write(b);
286             // increase filepointer by written byte
287
filepointer++;
288         }
289         else
290         {
291             // create next volume
292
this.createStreamToNextVolume();
293             zippedoutputstream.write(b);
294             // increase filepointer by written byte
295
filepointer++;
296         }
297     }
298
299     /**
300      * @see java.io.OutputStream#flush()
301      */

302     public void flush() throws IOException JavaDoc
303     {
304         zippedoutputstream.flush();
305         fileoutputstream.flush();
306     }
307
308     /**
309      * Returns the amount of currently created volumes
310      *
311      * @return the amount of created volumes
312      */

313     public int getVolumeCount()
314     {
315         return this.currentvolumeindex + 1;
316     }
317
318     /**
319      *
320      * @return
321      */

322     public long getFirstvolumefreespacesize()
323     {
324         return firstvolumefreespacesize;
325     }
326
327     /**
328      *
329      * @param firstvolumefreespacesize
330      */

331     public void setFirstvolumefreespacesize(long firstvolumefreespacesize)
332     {
333         this.firstvolumefreespacesize = firstvolumefreespacesize;
334     }
335
336     /**
337      * Returns the current position in this file
338      *
339      * @return the position in this file
340      * @throws IOException
341      */

342     public long getCompressedFilepointer() throws IOException JavaDoc
343     {
344         this.flush();
345         // return filepointer;
346
return totalbytesofpreviousvolumes + currentfile.length();
347     }
348
349     public long getFilepointer()
350     {
351         return filepointer;
352     }
353 }
354
Popular Tags