package org.agnitas.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.log4j.Logger;
/**
* Utility class dealing with files and streams.
*
* @author md
*/
public class FileUtils {
/** Logger used by this class. */
private static final transient Logger logger = Logger.getLogger( FileUtils.class);
/**
* Exception indicating, that a given ZIP entry was not found in ZIP file.
*
* @author md
*/
public static class ZipEntryNotFoundException extends Exception {
/** Name of the ZIP entry. */
private final String zipEntryName;
/**
* Creates a new exception.
*
* @param zipEntryName name of the ZIP entry
*/
public ZipEntryNotFoundException( String zipEntryName) {
super( "ZIP entry not found: " + zipEntryName);
this.zipEntryName = zipEntryName;
}
/**
* Returns the name of the ZIP entry.
*
* @return name of the ZIP entry
*/
public String getZipEntryName() {
return this.zipEntryName;
}
}
/**
* Extracts a given entry from a ZIP file to a temporary file.
* The temporary file must be handled by the caller. No "deleteOnExit()" is called
* to that file.
*
* @param zipFile ZIP file to use
* @param entryName name of the ZIP entry to extract
* @param tempFilePrefix prefix for the temporary file
*
* @return the temporary file
*
* @throws IOException on errors during extraction of ZIP entry
* @throws ZipEntryNotFoundException when the ZIP entry does not exist in the ZIP file
*/
public static File extractZipEntryToTemporaryFile( ZipFile zipFile, String entryName, String tempFilePrefix) throws IOException, ZipEntryNotFoundException {
if( logger.isDebugEnabled()) {
logger.debug( "Transferring data from ZIP entry to temporary file");
}
File file = File.createTempFile( tempFilePrefix, null);
extractZipEntryToFile( zipFile, entryName, file);
return file;
}
/**
* Extracts an entry of a given ZIP file to a specific destination file.
*
* @param zipFile ZIP file to use
* @param entryName name of the ZIP entry
* @param destinationFile file to extract to
*
* @throws ZipEntryNotFoundException when the ZIP entry was not found in the ZIP file
* @throws IOException on errors during extraction
*/
public static void extractZipEntryToFile( ZipFile zipFile, String entryName, File destinationFile) throws ZipEntryNotFoundException, IOException {
if( logger.isDebugEnabled()) {
logger.debug( "Transferring ZIP entry " + entryName + " from ZIP file " + zipFile.getName() + " to " + destinationFile.getAbsolutePath());
}
ZipEntry zipEntry = zipFile.getEntry( entryName);
if( zipEntry == null) {
logger.info( "ZIP entry not found: " + entryName);
throw new ZipEntryNotFoundException( entryName);
}
InputStream inputStream = zipFile.getInputStream( zipEntry);
try {
streamToFile( inputStream, zipEntry.getSize(), destinationFile);
} finally {
inputStream.close();
}
}
public static void extractZipEntryToStream( ZipFile zipFile, String entryName, OutputStream outputStream) throws ZipEntryNotFoundException, IOException {
if( logger.isDebugEnabled()) {
logger.debug( "Transferring ZIP entry " + entryName + " from ZIP file " + zipFile.getName() + " to stream");
}
ZipEntry zipEntry = zipFile.getEntry( entryName);
if( zipEntry == null) {
logger.info( "ZIP entry not found: " + entryName);
throw new ZipEntryNotFoundException( entryName);
}
InputStream inputStream = zipFile.getInputStream( zipEntry);
try {
streamToStream( inputStream, zipEntry.getSize(), outputStream);
} finally {
inputStream.close();
}
}
/**
byte[] buffer = new byte[16384];
long remaining = lengthOfData;
int read;
while( remaining > 0) {
read = inputStream.read( buffer);
remaining -= read;
outputStream.write( buffer, 0, read);
}
* Writes data from an InputStream to a temporary file. The size of data to
* be transferred must be known in order to use this method. The caller must handle
* the temporary file. No "deleteOnExit()" is called to that file.
* The caller also has to handle the InputStream. It is not closed by this method.
*
* @param inputStream InputStream to read from
* @param lengthOfData number of bytes to be transferred
* @param tempFilePrefix prefix of the temporary file
*
* @return the temporary file containing the data
*
* @throws IOException on errors reading from the stream
*/
public static File streamToTemporaryFile( InputStream inputStream, long lengthOfData, String tempFilePrefix) throws IOException {
if( logger.isDebugEnabled()) {
logger.debug( "Transferring data from stream to temporary file");
}
File file = File.createTempFile( tempFilePrefix, null);
streamToFile( inputStream, lengthOfData, file);
return file;
}
/**
* Writes data from an InputStream to a temporary file. The size of data to
* be transferred must be known in order to use this method.
* The caller has to handle the InputStream. It is not closed by this method.
*
* @param inputStream InputStream to read from
* @param lengthOfData number of bytes to be transferred
* @param file file to write data
*
* @throws IOException on errors reading from the stream
*/
public static void streamToFile( InputStream inputStream, long lengthOfData, File file) throws IOException {
if( logger.isDebugEnabled()) {
logger.debug( "Transferring " + lengthOfData + " bytes from stream to file " + file.getAbsolutePath());
}
FileOutputStream outputStream = new FileOutputStream( file);
try {
streamToStream( inputStream, lengthOfData, outputStream);
} finally {
outputStream.close();
}
}
public static void streamToStream( InputStream inputStream, long lengthOfData, OutputStream outputStream) throws IOException {
byte[] buffer = new byte[16384]; // Data buffer
long remaining = lengthOfData; // remaining bytes to read
int read; // bytes read in iteration
while( remaining > 0) {
read = inputStream.read( buffer);
remaining -= read;
outputStream.write( buffer, 0, read);
}
}
public static void copyFileToDirectory( File sourceFile, File destinationDirectory) throws IOException {
if( !destinationDirectory.isDirectory())
throw new IllegalArgumentException( "destination is not a directory: " + destinationDirectory.getAbsolutePath());
File destinationFile = new File( destinationDirectory.getCanonicalPath() + File.separator + sourceFile.getName());
FileInputStream inputStream = new FileInputStream( sourceFile);
try {
streamToFile( inputStream, sourceFile.length(), destinationFile);
} catch( IOException e) {
logger.error( "Error copying file (" + sourceFile.getAbsolutePath() + " to directory " + destinationDirectory.getAbsolutePath() + ")", e);
throw e;
} finally {
inputStream.close();
}
}
public static void createPathToFile( File file) {
File parent = file.getParentFile();
if( logger.isDebugEnabled()) {
logger.debug( "Creating directory structure " + parent.getAbsolutePath() + " for file " + file.getAbsolutePath());
}
parent.mkdirs();
}
public static void createPath( String path) {
File file = new File( path);
if( logger.isDebugEnabled()) {
logger.debug( "Creating directory structure for " + file.getAbsolutePath());
}
file.mkdirs();
}
public static String removeTrailingSeparator( String path) {
String correctedPath = path;
while( correctedPath.endsWith( File.separator))
correctedPath = correctedPath.substring( 0, correctedPath.lastIndexOf( File.separator));
if( logger.isDebugEnabled()) {
logger.debug( "Corrected path " + path + " to " + correctedPath);
}
return correctedPath;
}
public static boolean removeRecursively( String name) {
File file = new File( name);
return removeRecursively( file);
}
public static boolean removeRecursively( File file) {
if( file.isDirectory()) {
File[] containedFiles = file.listFiles();
for( File containedFile : containedFiles) {
if( !removeRecursively( containedFile))
return false;
}
}
return file.delete();
}
}