/*
* $Id$
*
* Copyright 2006, The jCoderZ.org Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the jCoderZ.org Project nor the names of
* its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jcoderz.commons.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
/**
* This class collects some nifty file utility functions.
*
* TODO: Cleanup check vs. IoUtil
*
* @author Michael Griffel
* @author Andreas Mandel
*/
public final class FileUtils
{
private static final int RND_FILENAME_FACTOR = 100000;
private static final int BUFFER_SIZE = 4096;
/**
* Only utility functions -- no instances allowed.
*/
private FileUtils ()
{
// no instances allowed - provides only static utility functions
}
/**
* Copies the file or directory <code>src</code> to the
* directory <code>destinationDir</code>.
*
* @param src the source file or directory.
* @param destinationDir the destination directory.
* @throws IOException in case of an I/O error.
*/
public static void copy (File src, File destinationDir)
throws IOException
{
if (src.isFile())
{
copyFile(src, destinationDir);
}
else if (src.isDirectory())
{
final File subdir = new File(destinationDir, src.getName());
if (!subdir.exists())
{
if (!subdir.mkdir())
{
throw new IOException("Failed to create subdir '" + subdir
+ "'.");
}
}
final File [] files = src.listFiles();
for (int i = 0; i < files.length; i++)
{
copy(files[i], subdir);
}
}
}
/**
* Copies the file <code>src</code> to the file or directory
* <code>dest</code>.
*
* @param src The source file.
* @param dest The destination file or directory.
* @throws FileNotFoundException if the source file does not exists.
* @throws IOException in case of an I/O error.
*/
public static void copyFile (File src, File dest)
throws FileNotFoundException, IOException
{
FileInputStream in = null;
FileOutputStream out = null;
try
{
in = new FileInputStream(src);
if (dest.isDirectory())
{
out = new FileOutputStream(new File(dest, src.getName()));
}
else
{
out = new FileOutputStream(dest);
}
copy(in, out);
}
finally
{
close(in);
close(out);
}
}
/**
* Copy from an input stream to an output stream.
*
* @param in The input stream.
* @param out The output stream.
* @throws IOException when an error happens during a read or a write
* operation.
*/
public static void copy (InputStream in, OutputStream out)
throws IOException
{
final byte[] buffer = new byte[BUFFER_SIZE];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
}
/**
* Copy all files under <code>srcDir</code> to the directory
* <code>dst</code>.
*
* Unix command:
* <pre>
* $ cp "$scrDir/*" "$dst"
* </pre>
*
* @param srcDir the source directory.
* @param dst the destination directory.
* @throws IOException in case of an I/O error.
*/
public static void copySlashStar (File srcDir, File dst)
throws IOException
{
if (srcDir.isDirectory())
{
final File[] files = srcDir.listFiles();
for (int i = 0; i < files.length; i++)
{
copy(files[i], dst);
}
}
else
{
throw new IllegalArgumentException("Souce must be a directory. ('"
+ srcDir + "')");
}
}
/**
* Creates a temporary directory.
* @param baseDir the base directory.
* @param prefix prefix for the temporary directory.
* @return a temporary directory.
* @throws IOException in case of an I/O error.
*/
public static File createTempDir (File baseDir, String prefix)
throws IOException
{
final String dirname = prefix
+ String.valueOf((int) (Math.random() * RND_FILENAME_FACTOR));
final File tempDir = new File(baseDir, dirname);
if (! tempDir.mkdir())
{
throw new IOException("Cannot create temp directory '"
+ tempDir + "'");
}
return tempDir;
}
/**
* Closes the input stream (safe).
*
* This method tries to close the given input stream and
* if an IOException occurs a message with the level
* {@link Level#FINE} is logged. It's safe to pass a
* <code>null</code> reference for the argument.
*
* @param in the input stream that should be closed.
* @deprecated use IoUtil.close(InputStream)
*/
public static void close (InputStream in)
{
IoUtil.close(in);
}
/**
* Closes the output stream (safe).
*
* This method tries to close the given output stream and
* if an IOException occurs a message with the level
* {@link Level#FINE} is logged. It's safe to pass a
* <code>null</code> reference for the argument.
*
* @param out the output stream that should be closed.
* @deprecated use IoUtil.close(OutputStream)
*/
public static void close (OutputStream out)
{
IoUtil.close(out);
}
/**
* Closes the reader (safe).
*
* This method tries to close the given reader and if an IOException occurs
* a message with the level {@link Level#FINE} is logged. It's safe
* to pass a <code>null</code> reference for the argument.
*
* @param reader the reader that should be closed.
* @deprecated use IoUtil.close(Reader)
*/
public static void safeClose (Reader reader)
{
IoUtil.close(reader);
}
/**
* Closes the writer (safe).
*
* This method tries to close the given writer and if an IOException occurs
* a message with the level {@link Level#FINE} is logged. It's safe
* to pass a <code>null</code> reference for the argument.
*
* @param writer the writer that should be closed.
* @deprecated use IoUtil.close(Writer)
*/
public static void safeClose (Writer writer)
{
IoUtil.close(writer);
}
/**
* Search for files in a directory hierarchy.
*
* Unix command:
* <pre>
* find path -name pattern
* </pre>
* @param path root directory.
* @param pattern filename pattern.
* @return a list of files matching the given <code>pattern</code>
* under <code>path</code>.
*/
public static List findFile (File path, String pattern)
{
final List ret = new ArrayList();
// Check whether the path exists
if (!path.exists())
{
throw new IllegalArgumentException(
"The specified path does not exist! ('"
+ path + "')");
}
findFile(path, pattern, ret);
return ret;
}
private static void findFile (File file, String pattern, List found)
{
if (file.isDirectory())
{
final File[] files = file.listFiles();
for (int i = 0; i < files.length; i++)
{
findFile(files[i], pattern, found);
}
}
else
{
if (file.getName().matches(pattern))
{
found.add(file);
}
}
}
/**
* Remove file or directory.
*
* Unix command:
* <pre>
* rm -rf file
* </pre>
* @param file the file or directory to delete.
* @throws IOException in case of an I/O error.
*/
public static void rmdir (File file)
throws IOException
{
if (file == null)
{
// done...
}
else if (file.isDirectory())
{
final File [] files = file.listFiles();
for (int i = 0; i < files.length; i++)
{
rmdir(files[i]);
}
if (!file.delete())
{
throw new IOException("Failed to delete directory " + file + ".");
}
}
else
{
if (!file.delete())
{
throw new IOException("Failed to delete file " + file + ".");
}
}
}
/**
* Returns the relative path of <code>file</code> to the file
* <code>basedir</code>.
* @param baseDir the base directory or file.
* @param file the file.
* @return the relative path of the file to the basedir.
* @throws IOException in case of an I/O error.
*/
public static String getRelativePath (File baseDir, File file)
throws IOException
{
final String base = baseDir.getCanonicalPath();
String fileName = file.getCanonicalPath();
if (fileName.startsWith(base))
{
fileName = fileName.substring(base.length());
if (fileName.charAt(0) == '/')
{
fileName = fileName.substring(1);
}
}
else
{
throw new RuntimeException("Cannot add file '" + file
+ "' with different baseDir '" + baseDir + "'.");
}
return fileName;
}
/**
* Renames the file <code>aFile</code>.
*
* @param aFile The file to be renamed.
* @param dest The new abstract pathname for the named file
* @throws IOException if the the renaming was not successful.
*/
public static void rename (File aFile, File dest)
throws IOException
{
if (!aFile.renameTo(dest))
{
throw new IOException("Failed to rename " + aFile + " to " + dest);
}
}
/**
* Deletes the given file <code>aFile</code>.
*
* @param aFile The file to be deleted.
* @throws IOException if the the deletion was not successful.
*/
public static void delete (File aFile)
throws IOException
{
if (aFile.exists())
{
if (!aFile.delete())
{
throw new IOException("Failed to delete " + aFile);
}
}
}
/**
* Creates the given directories.
*
* @param dirs the directories to be created.
* @throws IOException the directories could not be created.
* @see File#mkdirs()
*/
public static void mkdirs (File dirs)
throws IOException
{
if (!dirs.exists() || !dirs.isDirectory())
{
if (!dirs.mkdirs())
{
throw new IOException("Failed to create directories " + dirs);
}
}
}
/**
* Creates the given directory.
*
* @param dir the directory to be created.
* @throws IOException if the file could not be created.
* @see File#mkdir()
*/
public static void mkdir (File dir)
throws IOException
{
if (!dir.exists() || !dir.isDirectory())
{
if (!dir.mkdir())
{
throw new IOException("Failed to create directory " + dir);
}
}
}
/**
* Creates the given file.
* @param newFile the file to create
* @throws IOException the file could not be created.
* @see File#createNewFile()
*/
public static void createNewFile (File newFile)
throws IOException
{
if (!newFile.createNewFile())
{
throw new IOException("Failed to create new File " + newFile);
}
}
}