Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
*
* http://izpack.org/ http://izpack.codehaus.org/
*
* Copyright 2007 Dennis Reil
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.izforge.izpack.io;
import com.izforge.izpack.util.Debug;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Random;
import java.util.zip.GZIPOutputStream;
/**
* An outputstream which transparently spans over multiple volumes. The size of the volumes and an
* additonal space for the first volume can be specified.
*
* @author Dennis Reil,
*/
public class FileSpanningOutputStream extends OutputStream
{
public static final long KB = 1000;
public static final long MB = 1000 * KB;
// the default size of a volume
public static final long DEFAULT_VOLUME_SIZE = 650 * MB;
// free space on first volume
// may be used for placing additional files on cd beside the pack files
// default is 0, so there's no additional space
public static final long DEFAULT_ADDITIONAL_FIRST_VOLUME_FREE_SPACE_SIZE = 0;
// the default volume name
protected static final String DEFAULT_VOLUME_NAME = "rdpack";
protected static final long FILE_NOT_AVAILABLE = -1;
// the maximum size of a volume
protected long maxvolumesize = DEFAULT_VOLUME_SIZE;
// the addition free space of volume 0
protected long firstvolumefreespacesize = DEFAULT_ADDITIONAL_FIRST_VOLUME_FREE_SPACE_SIZE;
public static final String VOLUMES_INFO = "/volumes.info";
public static final int MAGIC_NUMER_LENGTH = 10;
// the current file this stream writes to
protected File currentfile;
// the name of the volumes
protected String volumename;
// the current index of the volume, the stream writes to
protected int currentvolumeindex;
// a normal file outputstream for writting to the current volume
private FileOutputStream fileoutputstream;
private GZIPOutputStream zippedoutputstream;
//
private byte[] magicnumber;
// the current position in the open file
protected long filepointer;
protected long totalbytesofpreviousvolumes;
/**
* Creates a new spanning output stream with specified volume names and a maximum volume size
*
* @param volumename - the name of the volumes
* @param maxvolumesize - the maximum volume size
* @throws IOException
*/
public FileSpanningOutputStream(String volumename, long maxvolumesize) throws IOException
{
this(new File(volumename), maxvolumesize);
}
/**
* Creates a new spanning output stream with specified volume names and a maximum volume size
*
* @param volume - the first volume
* @param maxvolumesize - the maximum volume size
* @throws IOException
*/
public FileSpanningOutputStream(File volume, long maxvolumesize) throws IOException
{
this(volume, maxvolumesize, 0);
}
/**
* Creates a new spanning output stream with specified volume names and a maximum volume size
*
* @param volume - the first volume
* @param maxvolumesize - the maximum volume size
* @param currentvolume - the current volume
* @throws IOException
*/
protected FileSpanningOutputStream(File volume, long maxvolumesize, int currentvolume)
throws IOException
{
this.generateMagicNumber();
this.createVolumeOutputStream(volume, maxvolumesize, currentvolume);
}
private void generateMagicNumber()
{
// only create a magic number, if not already done
if (magicnumber == null)
{
// create empty magic number
magicnumber = new byte[MAGIC_NUMER_LENGTH];
Date currenttime = new Date();
long currenttimeseconds = currenttime.getTime();
// create random number generator
Random random = new Random(currenttimeseconds);
random.nextBytes(magicnumber);
Debug.trace("created new magic number for FileOutputstream: "
+ new String(magicnumber));
for (int i = 0; i < magicnumber.length; i++)
{
Debug.trace(i + " - " + magicnumber[i]);
}
}
}
/**
* Actually creates the outputstream for writing a volume with index currentvolume and a maximum
* of maxvolumesize
*
* @param volume - the volume to write to
* @param maxvolumesize - the maximum volume size
* @param currentvolume - the currentvolume index
* @throws IOException
*/
private void createVolumeOutputStream(File volume, long maxvolumesize, int currentvolume)
throws IOException
{
fileoutputstream = new FileOutputStream(volume);
zippedoutputstream = new GZIPOutputStream(fileoutputstream, 256);
currentfile = volume;
this.currentvolumeindex = currentvolume;
this.maxvolumesize = maxvolumesize;
// try to get the volumename from the given volume file
// the first volume has no suffix, additional volumes have a .INDEX# suffix
String volumesuffix = "." + currentvolume;
String volabsolutePath = volume.getAbsolutePath();
if (volabsolutePath.endsWith(volumesuffix))
{
volumename = volabsolutePath.substring(0, volabsolutePath.indexOf(volumesuffix));
}
else
{
volumename = volabsolutePath;
}
long oldfilepointer = filepointer;
// write magic number into output stream
this.write(magicnumber);
// reset filepointer
filepointer = oldfilepointer;
}
/**
* @param volume
* @throws IOException
*/
public FileSpanningOutputStream(File volume) throws IOException
{
this(volume.getAbsolutePath(), DEFAULT_VOLUME_SIZE);
}
/**
* @param volumename
* @throws IOException
*/
public FileSpanningOutputStream(String volumename) throws IOException
{
this(volumename, DEFAULT_VOLUME_SIZE);
}
/**
* @throws IOException
*/
public FileSpanningOutputStream() throws IOException
{
this(DEFAULT_VOLUME_NAME, DEFAULT_VOLUME_SIZE);
}
/**
* Returns the size of the current volume
*
* @return the size of the current volume FILE_NOT_AVAILABLE, if there's no current volume
*/
protected long getCurrentVolumeSize()
{
if (currentfile == null)
{
return FILE_NOT_AVAILABLE;
}
try
{
flush();
}
catch (IOException e)
{
e.printStackTrace();
}
// create a new instance
currentfile = new File(currentfile.getAbsolutePath());
if (currentvolumeindex == 0)
{
// this is the first volume, add the additional free space
// and add a reserve for overhead and not yet written data
return currentfile.length() + this.firstvolumefreespacesize
+ Math.round(0.001 * currentfile.length());
}
else
{
// not the first volume, just return the actual length
// and add a reserve for overhead and not yet written data
return currentfile.length() + Math.round(0.001 * currentfile.length());
}
}
/**
* Closes the stream to the current volume and reopens to the next volume
*
* @throws IOException
*/
protected void createStreamToNextVolume() throws IOException
{
// close current stream
close();
totalbytesofpreviousvolumes = currentfile.length();
currentvolumeindex++;
// get the name of the next volume
String nextvolumename = volumename + "." + currentvolumeindex;
// does the creation
this.createVolumeOutputStream(new File(nextvolumename), this.maxvolumesize,
this.currentvolumeindex);
}
/**
* @see java.io.OutputStream#close()
*/
public void close() throws IOException
{
this.flush();
zippedoutputstream.close();
fileoutputstream.close();
// reset the filepointer
// filepointer = 0;
}
/**
* @see java.io.OutputStream#write(byte[], int, int)
*/
public void write(byte[] b, int off, int len) throws IOException
{
if (len > maxvolumesize)
{
throw new IOException(
"file can't be written. buffer length exceeded maxvolumesize (" + " > "
+ maxvolumesize + ")");
}
// get the current size of this file
long currentsize = getCurrentVolumeSize();
// calculate the available bytes
long available = maxvolumesize - currentsize;
if (available < len)
{
Debug.trace("Not enough space left on volume. available: " + available);
Debug.trace("current size is: " + currentsize);
// there's not enough space available
// create the next volume
this.createStreamToNextVolume();
}
// enough space available, just write to the outputstream
zippedoutputstream.write(b, off, len);
// increase filepointer by written bytes
filepointer += len;
}
/**
* @see java.io.OutputStream#write(byte[])
*/
public void write(byte[] b) throws IOException
{
this.write(b, 0, b.length);
}
/**
* @see java.io.OutputStream#write(int)
*/
public void write(int b) throws IOException
{
long availablebytes = maxvolumesize - getCurrentVolumeSize();
if (availablebytes >= 1)
{
zippedoutputstream.write(b);
// increase filepointer by written byte
filepointer++;
}
else
{
// create next volume
this.createStreamToNextVolume();
zippedoutputstream.write(b);
// increase filepointer by written byte
filepointer++;
}
}
/**
* @see java.io.OutputStream#flush()
*/
public void flush() throws IOException
{
zippedoutputstream.flush();
fileoutputstream.flush();
}
/**
* Returns the amount of currently created volumes
*
* @return the amount of created volumes
*/
public int getVolumeCount()
{
return this.currentvolumeindex + 1;
}
/**
* @return
*/
public long getFirstvolumefreespacesize()
{
return firstvolumefreespacesize;
}
/**
* @param firstvolumefreespacesize
*/
public void setFirstvolumefreespacesize(long firstvolumefreespacesize)
{
this.firstvolumefreespacesize = firstvolumefreespacesize;
}
/**
* Returns the current position in this file
*
* @return the position in this file
* @throws IOException
*/
public long getCompressedFilepointer() throws IOException
{
this.flush();
// return filepointer;
return totalbytesofpreviousvolumes + currentfile.length();
}
public long getFilepointer()
{
return filepointer;
}
}