You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by je...@apache.org on 2003/11/22 21:44:48 UTC

cvs commit: jakarta-commons-sandbox/io/src/java/org/apache/commons/io FileUtils.java

jeremias    2003/11/22 12:44:48

  Modified:    io/src/java/org/apache/commons/io FileUtils.java
  Log:
  I've moved some methods around while cleaning up, so, sorry for the big diff. I moved up the methods I checked through. There's a marker in the lower half of the file indicating where I progressed. Everything below that marker still has to be sorted out. I consider the stuff above that marker cleaned up and reviewed to a certain degree.
  
  Real changes are:
  - new method: touch(File)
  - some method signatures rewritten to use java.io.File instead of String, because it's this class' policy. This might break dependant projects.
  - updated some javadocs
  - Removed getFilesFromExtension (this method wants to do too much). This might break dependant projects.
  - Replacement for getFilesFromExtension, new method(s): listFiles which is implemented using the filefilter package. The CVS filter functionality of getFilesFromExtension can be achieved by using FileFilterUtils.makeCVSAware.
  
  Revision  Changes    Path
  1.17      +836 -681  jakarta-commons-sandbox/io/src/java/org/apache/commons/io/FileUtils.java
  
  Index: FileUtils.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/io/src/java/org/apache/commons/io/FileUtils.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- FileUtils.java	17 Oct 2003 20:15:46 -0000	1.16
  +++ FileUtils.java	22 Nov 2003 20:44:48 -0000	1.17
  @@ -59,11 +59,20 @@
   import java.io.FileOutputStream;
   import java.io.IOException;
   import java.io.InputStream;
  +import java.io.FileFilter;
  +import java.io.OutputStream;
   import java.net.URL;
   import java.util.ArrayList;
   import java.util.Collection;
   import java.util.Date;
   
  +import org.apache.commons.io.filefilter.DirectoryFileFilter;
  +import org.apache.commons.io.filefilter.FalseFileFilter;
  +import org.apache.commons.io.filefilter.FileFilterUtils;
  +import org.apache.commons.io.filefilter.IOFileFilter;
  +import org.apache.commons.io.filefilter.SuffixFileFilter;
  +import org.apache.commons.io.filefilter.TrueFileFilter;
  +
   /**
    * This class provides basic facilities for manipulating files and file paths.
    *
  @@ -107,6 +116,7 @@
    * @author <a href="mailto:peter@apache.org">Peter Donald</a>
    * @author <a href="mailto:jefft@apache.org">Jeff Turner</a>
    * @author Matthew Hawthorne
  + * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
    * @version $Id$
    */
   public class FileUtils {
  @@ -114,17 +124,17 @@
       /**
        * The number of bytes in a kilobyte.
        */
  -    public static final int ONE_KB = 1024;
  +    public static final long ONE_KB = 1024;
   
       /**
        * The number of bytes in a megabyte.
        */
  -    public static final int ONE_MB = ONE_KB * ONE_KB;
  +    public static final long ONE_MB = ONE_KB * ONE_KB;
   
       /**
        * The number of bytes in a gigabyte.
        */
  -    public static final int ONE_GB = ONE_KB * ONE_MB;
  +    public static final long ONE_GB = ONE_KB * ONE_MB;
   
       /**
        * Returns a human-readable version of the file size (original is in
  @@ -132,8 +142,9 @@
        *
        * @param size The number of bytes.
        * @return     A human-readable display value (includes units).
  +     * @todo need for I18N?
        */
  -    public static String byteCountToDisplaySize(int size) {
  +    public static String byteCountToDisplaySize(long size) {
           String displaySize;
   
           if (size / ONE_GB > 0) {
  @@ -150,216 +161,132 @@
       }
   
   
  -
       /**
  -     * Check if a file exits.
  -     *
  -     * @param fileName The name of the file to check.
  -     * @return true if file exists.
  -     */
  -    public static boolean fileExists(String fileName) {
  -        File file = new File(fileName);
  -        return file.exists();
  +     * Implements the same behaviour as the "touch" utility on Unix. It creates
  +     * a new file with size 0 or, if the file exists already, it is opened and
  +     * closed without modifying it, but updating the file date and time.
  +     * @param file the File to touch
  +     * @throws IOException If an I/O problem occurs
  +     */
  +    public static void touch(File file) throws IOException {
  +        OutputStream out = new java.io.FileOutputStream(file, true);
  +        out.close();
       }
   
  -    /**
  -     * Reads the contents of a file (using the default encoding).
  -     *
  -     * @param fileName The name of the file to read.
  -     * @return The file contents or null if read failed.
  -     * @throws IOException in case of an I/O error
  -     * TODO This method should probably be removed or rethought.
  -     * Because it uses the default encoding only it should probably not be
  -     * used at all (platform-dependency)
  -     */
  -    public static String fileRead(final String fileName) throws IOException {
  -        FileInputStream in = new FileInputStream(fileName);
  -        try {
  -            return IOUtils.toString(in);
  -        } finally {
  -            IOUtils.shutdownStream(in);
  -        }
  -    }
   
  -    /**
  -     * Writes data to a file. The file will be created if it does not exist.
  -     *
  -     * @param fileName The name of the file to write.
  -     * @param data The content to write to the file.
  -     * @throws IOException in case of an I/O error
  -     * TODO This method should probably be removed or rethought.
  -     * Because it uses the default encoding only it should probably not be
  -     * used at all (platform-dependency)
  -     */
  -    public static void fileWrite(String fileName, String data)
  -        throws IOException {
  -        FileOutputStream out = new FileOutputStream(fileName);
  -        try {
  -            out.write(data.getBytes());
  -        } finally {
  -            IOUtils.shutdownStream(out);
  +    private static void innerListFiles(Collection files, File directory, IOFileFilter filter) {
  +        File[] found = directory.listFiles((FileFilter)filter);
  +        for (int i = 0; i < found.length; i++) {
  +            if (found[i].isDirectory()) {
  +                innerListFiles(files, found[i], filter);
  +            } else {
  +                files.add(found[i]);
  +            }
           }
       }
   
   
  -
       /**
  -     * Deletes a file.
  -     *
  -     * @param fileName The name of the file to delete.
  +     * Converts a Collection containing java.io.File instanced into array
  +     * representation. This is to account for the difference between
  +     * File.listFiles() and FileUtilsNew.listFiles().
  +     * @param files a Collection containing java.io.File instances
  +     * @return an array of java.io.File
        */
  -    public static void fileDelete(String fileName) {
  -        File file = new File(fileName);
  -        file.delete();
  +    public File[] convertFileCollectionToFileArray(Collection files) {
  +         return (File[])files.toArray(new File[files.size()]);
       }
   
  -    /**
  -     * Waits for NFS to propagate a file creation, imposing a timeout.
  -     *
  -     * @param fileName The name of the file.
  -     * @param seconds The maximum time in seconds to wait.
  -     * @return True if file exists.
  -     * TODO Does this method make sense? Does it behave as it should?
  -     */
  -    public static boolean waitFor(String fileName, int seconds) {
  -        File file = new File(fileName);
  -        int timeout = 0;
  -        int tick = 0;
  -        while (!file.exists()) {
  -            if (tick++ >= 10) {
  -                tick = 0;
  -                if (timeout++ > seconds) {
  -                    return false;
  -                }
  -            }
  -            try {
  -                Thread.sleep(100);
  -            } catch (InterruptedException ignore) {} catch (Exception ex) {
  -                break;
  -            }
  -        }
  -        return true;
  -    }
   
       /**
  -     * Given a directory and an array of extensions... return an array of
  -     * compliant files.
  -     *
  -     * TODO Should an ignore list be passed in?
  -     * TODO Should a recurse flag be passed in?
  -     * TODO Should be rewritten using the filefilter package.
  -     *
  -     * The given extensions should be like "java" and not like ".java"
  +     * <p>Finds files within a given directory (and optionally its 
  +     * subdirectories). All files found are filtered by an IOFileFilter.
  +     * </p>
  +     * <p>If your search should recurse into subdirectories you can pass in 
  +     * an IOFileFilter for directories. You don't need to bind a 
  +     * DirectoryFileFilter (via logical AND) to this filter. This method does 
  +     * that for you.
  +     * </p>
  +     * <p>An example: If you want to search through all directories called
  +     * "temp" you pass in <code>FileFilterUtils.NameFileFilter("temp")</code>
  +     * </p>
  +     * <p>Another common usage of this method is find files in a directory
  +     * tree but ignoring the directories generated CVS. You can simply pass
  +     * in <code>FileFilterUtils.makeCVSAware(null)</code>.
  +     * </p>  
  +     * @param directory the directory to search in
  +     * @param fileFilter filter to apply when finding files.
  +     * @param dirFilter optional filter to apply when finding subdirectories. 
  +     * If this parameter is null, subdirectories will not be included in the
  +     * search. Use TrueFileFilter.INSTANCE to match all directories.
  +     * @return an collection of java.io.File with the matching files
  +     * @see org.apache.commons.io.filefilter.FileFilterUtils
  +     * @see org.apache.commons.io.filefilter.NameFileFilter
        */
  -    public static String[] getFilesFromExtension(
  -        String directory,
  -        String[] extensions) {
  -
  -        Collection files = new ArrayList();
  -
  -        File currentDir = new File(directory);
  -
  -        String[] unknownFiles = currentDir.list();
  -
  -        if (unknownFiles == null) {
  -            return new String[0];
  +    public static Collection listFiles(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter) {
  +        if (!directory.isDirectory()) {
  +            throw new IllegalArgumentException("Parameter 'directory' is not a directory");
           }
  -
  -        for (int i = 0; i < unknownFiles.length; ++i) {
  -            String currentFileName =
  -                directory
  -                    + System.getProperty("file.separator")
  -                    + unknownFiles[i];
  -            File currentFile = new java.io.File(currentFileName);
  -
  -            if (currentFile.isDirectory()) {
  -
  -                //ignore all CVS directories...
  -                if (currentFile.getName().equals("CVS")) {
  -                    continue;
  -                }
  -
  -                //ok... transverse into this directory and get all the files... then combine
  -                //them with the current list.
  -
  -                String[] fetchFiles =
  -                    getFilesFromExtension(currentFileName, extensions);
  -                files = blendFiles(files, fetchFiles);
  -
  -            } else {
  -                //ok... add the file
  -
  -                String add = currentFile.getAbsolutePath();
  -                if (isValidFile(add, extensions)) {
  -                    files.add(add);
  -
  -                }
  -
  -            }
  +        if (fileFilter == null) {
  +            throw new NullPointerException("Parameter 'fileFilter' is null");
           }
  -
  -        //ok... move the Vector into the files list...
  -
  -        String[] foundFiles = new String[files.size()];
  -        files.toArray(foundFiles);
  -
  -        return foundFiles;
  -
  -    }
  -
  -    /**
  -     * Private hepler method for getFilesFromExtension()
  -     */
  -    private static Collection blendFiles(Collection c, String[] files) {
  -
  -        for (int i = 0; i < files.length; ++i) {
  -            c.add(files[i]);
  +        
  +        //Setup effective file filter
  +        IOFileFilter effFileFilter = FileFilterUtils.andFileFilter(fileFilter, 
  +            FileFilterUtils.notFileFilter(DirectoryFileFilter.INSTANCE));
  +            
  +        //Setup effective directory filter
  +        IOFileFilter effDirFilter;
  +        if (dirFilter == null) {
  +            effDirFilter = FalseFileFilter.INSTANCE;
  +        } else {
  +            effDirFilter = FileFilterUtils.andFileFilter(dirFilter,
  +                DirectoryFileFilter.INSTANCE);
           }
  -
  -        return c;
  +        
  +        //Find files
  +        Collection files = new java.util.LinkedList();
  +        innerListFiles(files, directory, 
  +            FileFilterUtils.orFileFilter(effFileFilter, effDirFilter));
  +        return files;
       }
  +    
   
       /**
  -     * Checks to see if a file is of a particular type(s).
  -     * Note that if the file does not have an extension, an empty string
  -     * (&quot;&quot;) is matched for.
  -     *
  +     * Converts an array of file extensions to suffixes for use
  +     * with IOFileFilters.
  +     * @param extensions an array of extensions. Format: {"java", "xml"}
  +     * @return an array of suffixes. Format: {".java", ".xml"}
        */
  -    private static boolean isValidFile(String file, String[] extensions) {
  -
  -        String extension = extension(file);
  -        if (extension == null) {
  -            extension = "";
  -        }
  -
  -        //ok.. now that we have the "extension" go through the current know
  -        //excepted extensions and determine if this one is OK.
  -
  -        for (int i = 0; i < extensions.length; ++i) {
  -            if (extensions[i].equals(extension))
  -                return true;
  +    public static String[] toSuffixes(final String[] extensions) {
  +        String[] suffixes = new String[extensions.length];
  +        for (int i = 0; i < extensions.length; i++) {
  +            suffixes[i] = "." + extensions[i];
           }
  -
  -        return false;
  -
  +        return suffixes;
       }
   
  +
       /**
  -     * Simple way to make a directory. It also creates the parent directories
  -     * if necessary.
  -     * @param dir directory to create
  +     * Finds files within a given directory (and optionally its subdirectories)
  +     * which match an array of extensions. 
  +     * @param directory the directory to search in
  +     * @param extensions an array of extensions, ex. {"java","xml"}. If this
  +     * parameter is null, all files are returned.
  +     * @param recursive If true all subdirectories are searched, too.
  +     * @return an collection of java.io.File with the matching files
        */
  -    public static void mkdir(String dir) {
  -        File file = new File(dir);
  -        if (!file.exists()) {
  -            file.mkdirs();
  -        }
  +    public static Collection listFiles(File directory, String[] extensions, boolean recursive) {
  +        String[] suffixes = toSuffixes(extensions);
  +        IOFileFilter filter = new SuffixFileFilter(suffixes);
  +        return listFiles(directory, filter, 
  +            (recursive ? TrueFileFilter.INSTANCE : FalseFileFilter.INSTANCE));
       }
   
  -    /* *** AVALON CODE *** */
   
       /**
  -     * Compare the contents of two files to determine if they are equal or not.
  +     * <p>Compare the contents of two files to determine if they are equal or not.</p>
  +     * <p>Code origin: Avalon</p>
        *
        * @param file1 the first file
        * @param file2 the second file
  @@ -367,7 +294,7 @@
        * @throws IOException in case of an I/O error
        */
       public static boolean contentEquals(final File file1, final File file2)
  -        throws IOException {
  +            throws IOException {
           final boolean file1Exists = file1.exists();
           if (file1Exists != file2.exists()) {
               return false;
  @@ -380,14 +307,14 @@
   
           if (file1.isDirectory() || file2.isDirectory()) {
               // don't want to compare directory contents
  -            return false;
  +            throw new IOException("Can't compare directories, only files");
           }
   
           InputStream input1 = null;
           InputStream input2 = null;
           try {
  -            input1 = new FileInputStream(file1);
  -            input2 = new FileInputStream(file2);
  +            input1 = new java.io.FileInputStream(file1);
  +            input2 = new java.io.FileInputStream(file2);
               return IOUtils.contentEquals(input1, input2);
   
           } finally {
  @@ -429,182 +356,61 @@
           return urls;
       }
   
  +
       /**
  -     * Remove extension from filename.
  -     * ie
  -     * <pre>
  -     * foo.txt    --> foo
  -     * a\b\c.jpg --> a\b\c
  -     * a\b\c     --> a\b\c
  -     * </pre>
  +     * Copy file from source to destination. If <code>destinationDirectory</code> does not exist, it
  +     * (and any parent directories) will be created. If a file <code>source</code> in
  +     * <code>destinationDirectory</code> exists, it will be overwritten.
        *
  -     * @param filename the filename
  -     * @return the filename minus extension
  +     * @param source An existing <code>File</code> to copy.
  +     * @param destinationDirectory A directory to copy <code>source</code> into.
  +     *
  +     * @throws FileNotFoundException if <code>source</code> isn't a normal file.
  +     * @throws IllegalArgumentException if <code>destinationDirectory</code> isn't a directory.
  +     * @throws IOException if <code>source</code> does not exist, the file in
  +     * <code>destinationDirectory</code> cannot be written to, or an IO error occurs during copying.
        */
  -    public static String removeExtension(final String filename) {
  -        final int index = filename.lastIndexOf('.');
  -
  -        if (-1 == index) {
  -            return filename;
  -        } else {
  -            return filename.substring(0, index);
  +    public static void copyFileToDirectory(
  +        final File source,
  +        final File destinationDirectory)
  +        throws IOException {
  +        if (destinationDirectory.exists()
  +            && !destinationDirectory.isDirectory()) {
  +            throw new IllegalArgumentException("Destination is not a directory");
           }
  +
  +        copyFile(source, new File(destinationDirectory, source.getName()));
       }
   
       /**
  -     * Get extension from filename.
  -     * ie
  -     * <pre>
  -     * foo.txt    --> "txt"
  -     * a\b\c.jpg --> "jpg"
  -     * a\b\c     --> ""
  -     * </pre>
  +     * Copy file from source to destination. The directories up to 
  +     * <code>destination</code> will be created if they don't already exist. 
  +     * <code>destination</code> will be overwritten if it already exists.
        *
  -     * @param filename the filename
  -     * @return the extension of filename or "" if none
  +     * @param source An existing non-directory <code>File</code> to copy 
  +     * bytes from.
  +     * @param destination A non-directory <code>File</code> to write bytes to 
  +     * (possibly overwriting).
  +     *
  +     * @throws IOException if <code>source</code> does not exist, <code>destination</code> cannot be
  +     * written to, or an IO error occurs during copying.
  +     *
  +     * @throws FileNotFoundException if <code>destination</code> is a directory
  +     * (use {@link #copyFileToDirectory}).
        */
  -    public static String getExtension(final String filename) {
  -        final int index = filename.lastIndexOf('.');
  -
  -        if (-1 == index) {
  -            return "";
  -        } else {
  -            return filename.substring(index + 1);
  +    public static void copyFile(final File source, final File destination)
  +        throws IOException {
  +        //check source exists
  +        if (!source.exists()) {
  +            final String message = "File " + source + " does not exist";
  +            throw new FileNotFoundException(message);
           }
  -    }
   
  -    /**
  -     * Remove path from filename. Equivalent to the unix command <code>basename</code>
  -     * ie.
  -     * <pre>
  -     * a/b/c.txt --> c.txt
  -     * a.txt     --> a.txt
  -     * </pre>
  -     *
  -     * @param filepath the filepath
  -     * @return the filename minus path
  -     */
  -    public static String removePath(final String filepath) {
  -        return removePath(filepath, File.separatorChar);
  -    }
  -
  -    /**
  -     * Remove path from filename.
  -     * ie.
  -     * <pre>
  -     * a/b/c.txt --> c.txt
  -     * a.txt     --> a.txt
  -     * </pre>
  -     *
  -     * @param filepath the filepath
  -     * @param fileSeparatorChar the file separator character to use
  -     * @return the filename minus path
  -     */
  -    public static String removePath(
  -        final String filepath,
  -        final char fileSeparatorChar) {
  -        final int index = filepath.lastIndexOf(fileSeparatorChar);
  -
  -        if (-1 == index) {
  -            return filepath;
  -        } else {
  -            return filepath.substring(index + 1);
  -        }
  -    }
  -
  -    /**
  -     * Get path from filename. Roughly equivalent to the unix command <code>dirname</code>.
  -     * ie.
  -     * <pre>
  -     * a/b/c.txt --> a/b
  -     * a.txt     --> ""
  -     * </pre>
  -     *
  -     * @param filepath the filepath
  -     * @return the filename minus path
  -     */
  -    public static String getPath(final String filepath) {
  -        return getPath(filepath, File.separatorChar);
  -    }
  -
  -    /**
  -     * Get path from filename.
  -     * ie.
  -     * <pre>
  -     * a/b/c.txt --> a/b
  -     * a.txt     --> ""
  -     * </pre>
  -     *
  -     * @param filepath the filepath
  -     * @param fileSeparatorChar the file separator character to use
  -     * @return the filename minus path
  -     */
  -    public static String getPath(
  -        final String filepath,
  -        final char fileSeparatorChar) {
  -        final int index = filepath.lastIndexOf(fileSeparatorChar);
  -        if (-1 == index) {
  -            return "";
  -        } else {
  -            return filepath.substring(0, index);
  -        }
  -    }
  -
  -
  -
  -    /**
  -     * Copy file from source to destination. If <code>destinationDirectory</code> does not exist, it
  -     * (and any parent directories) will be created. If a file <code>source</code> in
  -     * <code>destinationDirectory</code> exists, it will be overwritten.
  -     *
  -     * @param source An existing <code>File</code> to copy.
  -     * @param destinationDirectory A directory to copy <code>source</code> into.
  -     *
  -     * @throws FileNotFoundException if <code>source</code> isn't a normal file.
  -     * @throws IllegalArgumentException if <code>destinationDirectory</code> isn't a directory.
  -     * @throws IOException if <code>source</code> does not exist, the file in
  -     * <code>destinationDirectory</code> cannot be written to, or an IO error occurs during copying.
  -     */
  -    public static void copyFileToDirectory(
  -        final File source,
  -        final File destinationDirectory)
  -        throws IOException {
  -        if (destinationDirectory.exists()
  -            && !destinationDirectory.isDirectory()) {
  -            throw new IllegalArgumentException("Destination is not a directory");
  -        }
  -
  -        copyFile(source, new File(destinationDirectory, source.getName()));
  -    }
  -
  -    /**
  -     * Copy file from source to destination. The directories up to <code>destination</code> will be
  -     * created if they don't already exist. <code>destination</code> will be overwritten if it
  -     * already exists.
  -     *
  -     * @param source An existing non-directory <code>File</code> to copy bytes from.
  -     * @param destination A non-directory <code>File</code> to write bytes to (possibly
  -     * overwriting).
  -     *
  -     * @throws IOException if <code>source</code> does not exist, <code>destination</code> cannot be
  -     * written to, or an IO error occurs during copying.
  -     *
  -     * @throws FileNotFoundException if <code>destination</code> is a directory
  -     * (use {@link #copyFileToDirectory}).
  -     */
  -    public static void copyFile(final File source, final File destination)
  -        throws IOException {
  -        //check source exists
  -        if (!source.exists()) {
  -            final String message = "File " + source + " does not exist";
  -            throw new IOException(message);
  -        }
  -
  -        //does destinations directory exist ?
  -        if (destination.getParentFile() != null
  -            && !destination.getParentFile().exists()) {
  -            destination.getParentFile().mkdirs();
  -        }
  +        //does destinations directory exist ?
  +        if (destination.getParentFile() != null
  +            && !destination.getParentFile().exists()) {
  +            destination.getParentFile().mkdirs();
  +        }
   
           //make sure we can write to destination
           if (destination.exists() && !destination.canWrite()) {
  @@ -679,168 +485,154 @@
           }
       }
   
  +
       /**
  -     * Normalize a path.
  -     * Eliminates "/../" and "/./" in a string. Returns <code>null</code> if the ..'s went past the
  -     * root.
  -     * Eg:
  -     * <pre>
  -     * /foo//               -->     /foo/
  -     * /foo/./              -->     /foo/
  -     * /foo/../bar          -->     /bar
  -     * /foo/../bar/         -->     /bar/
  -     * /foo/../bar/../baz   -->     /baz
  -     * //foo//./bar         -->     /foo/bar
  -     * /../                 -->     null
  -     * </pre>
  -     *
  -     * @param path the path to normalize
  -     * @return the normalized String, or <code>null</code> if too many ..'s.
  +     * Recursively delete a directory.
  +     * @param directory directory to delete
  +     * @throws IOException in case deletion is unsuccessful
        */
  -    public static String normalize(final String path) {
  -        String normalized = path;
  -        // Resolve occurrences of "//" in the normalized path
  -        while (true) {
  -            int index = normalized.indexOf("//");
  -            if (index < 0)
  -                break;
  -            normalized =
  -                normalized.substring(0, index)
  -                    + normalized.substring(index + 1);
  -        }
  -
  -        // Resolve occurrences of "/./" in the normalized path
  -        while (true) {
  -            int index = normalized.indexOf("/./");
  -            if (index < 0)
  -                break;
  -            normalized =
  -                normalized.substring(0, index)
  -                    + normalized.substring(index + 2);
  +    public static void deleteDirectory(final File directory)
  +        throws IOException {
  +        if (!directory.exists()) {
  +            return;
           }
   
  -        // Resolve occurrences of "/../" in the normalized path
  -        while (true) {
  -            int index = normalized.indexOf("/../");
  -            if (index < 0)
  -                break;
  -            if (index == 0)
  -                return null; // Trying to go outside our context
  -            int index2 = normalized.lastIndexOf('/', index - 1);
  -            normalized =
  -                normalized.substring(0, index2)
  -                    + normalized.substring(index + 3);
  +        cleanDirectory(directory);
  +        if (!directory.delete()) {
  +            final String message =
  +                "Unable to delete directory " + directory + ".";
  +            throw new IOException(message);
           }
  -
  -        // Return the normalized path that we have completed
  -        return normalized;
       }
   
       /**
  -     * Will concatenate 2 paths.  Paths with <code>..</code> will be
  -     * properly handled.
  -     * <p>Eg.,<br />
  -     * <code>/a/b/c</code> + <code>d</code> = <code>/a/b/d</code><br />
  -     * <code>/a/b/c</code> + <code>../d</code> = <code>/a/d</code><br />
  -     * </p>
  -     *
  -     * Thieved from Tomcat sources...
  -     *
  -     * @return The concatenated paths, or null if error occurs
  +     * Clean a directory without deleting it.
  +     * @param directory directory to clean
  +     * @throws IOException in case cleaning is unsuccessful
        */
  -    public static String catPath(final String lookupPath, final String path) {
  -        // Cut off the last slash and everything beyond
  -        int index = lookupPath.lastIndexOf("/");
  -        String lookup = lookupPath.substring(0, index);
  -        String pth = path;
  +    public static void cleanDirectory(final File directory)
  +        throws IOException {
  +        if (!directory.exists()) {
  +            final String message = directory + " does not exist";
  +            throw new IllegalArgumentException(message);
  +        }
   
  -        // Deal with .. by chopping dirs off the lookup path
  -        while (pth.startsWith("../")) {
  -            if (lookup.length() > 0) {
  -                index = lookup.lastIndexOf("/");
  -                lookup = lookup.substring(0, index);
  -            } else {
  -                // More ..'s than dirs, return null
  -                return null;
  -            }
  +        if (!directory.isDirectory()) {
  +            final String message = directory + " is not a directory";
  +            throw new IllegalArgumentException(message);
  +        }
   
  -            index = pth.indexOf("../") + 3;
  -            pth = pth.substring(index);
  +        IOException exception = null;
  +
  +        final File[] files = directory.listFiles();
  +        for (int i = 0; i < files.length; i++) {
  +            final File file = files[i];
  +            try {
  +                forceDelete(file);
  +            } catch (final IOException ioe) {
  +                exception = ioe;
  +            }
           }
   
  -        return new StringBuffer(lookup).append("/").append(pth).toString();
  +        if (null != exception) {
  +            throw exception;
  +        }
       }
   
       /**
  -     * Resolve a file <code>filename</code> to it's canonical form. If <code>filename</code> is
  -     * relative (doesn't start with <code>/</code>), it will be resolved relative to
  -     * <code>baseFile</code>, otherwise it is treated as a normal root-relative path.
  +     * Waits for NFS to propagate a file creation, imposing a timeout.
        *
  -     * @param baseFile Where to resolve <code>filename</code> from, if <code>filename</code> is
  -     * relative.
  -     * @param filename Absolute or relative file path to resolve.
  -     * @return The canonical <code>File</code> of <code>filename</code>.
  +     * @param file The file
  +     * @param seconds The maximum time in seconds to wait.
  +     * @return True if file exists.
  +     * TODO Needs a clearer javadoc to see its real purpose for someone without
  +     *       NFS-knowledge.
        */
  -    public static File resolveFile(final File baseFile, String filename) {
  -        String filenm = filename;
  -        if ('/' != File.separatorChar) {
  -            filenm = filename.replace('/', File.separatorChar);
  +    public static boolean waitFor(final File file, final int seconds) {
  +        int timeout = 0;
  +        int tick = 0;
  +        while (!file.exists()) {
  +            if (tick++ >= 10) {
  +                tick = 0;
  +                if (timeout++ > seconds) {
  +                    return false;
  +                }
  +            }
  +            try {
  +                Thread.sleep(100);
  +            } catch (InterruptedException ignore) {} catch (Exception ex) {
  +                break;
  +            }
           }
  +        return true;
  +    }
   
  -        if ('\\' != File.separatorChar) {
  -            filenm = filename.replace('\\', File.separatorChar);
  -        }
  -
  -        // deal with absolute files
  -        if (filenm.startsWith(File.separator)) {
  -            File file = new File(filenm);
  -
  -            try {
  -                file = file.getCanonicalFile();
  -            } catch (final IOException ioe) {}
  -
  -            return file;
  -        }
  -        // FIXME: I'm almost certain this // removal is unnecessary, as getAbsoluteFile() strips
  -        // them. However, I'm not sure about this UNC stuff. (JT)
  -        final char[] chars = filename.toCharArray();
  -        final StringBuffer sb = new StringBuffer();
  -
  -        //remove duplicate file separators in succession - except
  -        //on win32 at start of filename as UNC filenames can
  -        //be \\AComputer\AShare\myfile.txt
  -        int start = 0;
  -        if ('\\' == File.separatorChar) {
  -            sb.append(filenm.charAt(0));
  -            start++;
  -        }
  -
  -        for (int i = start; i < chars.length; i++) {
  -            final boolean doubleSeparator =
  -                File.separatorChar == chars[i]
  -                    && File.separatorChar == chars[i - 1];
   
  -            if (!doubleSeparator) {
  -                sb.append(chars[i]);
  -            }
  +    /**
  +     * <p>
  +     * Reads the contents of a file into a String.
  +     * </p>
  +     * <p>
  +     * There is no readFileToString method without encoding parameter because
  +     * the default encoding can differ between platforms and therefore results
  +     * in inconsistent results.
  +     * </p>
  +     *
  +     * @param file the file to read.
  +     * @param encoding the encoding to use
  +     * @return The file contents or null if read failed.
  +     * @throws IOException in case of an I/O error
  +     * @throws UnsupportedEncodingException if the encoding is not supported
  +     *   by the VM
  +     */
  +    public static String readFileToString(
  +            final File file, final String encoding) throws IOException {
  +        InputStream in = new java.io.FileInputStream(file);
  +        try {
  +            return IOUtils.toString(in, encoding);
  +        } finally {
  +            IOUtils.shutdownStream(in);
           }
  +    }
   
  -        filenm = sb.toString();
  -
  -        //must be relative
  -        File file = (new File(baseFile, filenm)).getAbsoluteFile();
  -
  +    /**
  +     * <p>
  +     * Writes data to a file. The file will be created if it does not exist.
  +     * </p>
  +     * <p>
  +     * There is no readFileToString method without encoding parameter because
  +     * the default encoding can differ between platforms and therefore results
  +     * in inconsistent results.
  +     * </p>
  +     *
  +     * @param file the file to write.
  +     * @param data The content to write to the file.
  +     * @throws IOException in case of an I/O error
  +     * @throws UnsupportedEncodingException if the encoding is not supported
  +     *   by the VM
  +     */
  +    public static void writeStringToFile(final File file, 
  +            final String data, final String encoding) throws IOException {
  +        OutputStream out = new java.io.FileOutputStream(file);
           try {
  -            file = file.getCanonicalFile();
  -        } catch (final IOException ioe) {}
  -
  -        return file;
  +            out.write(data.getBytes(encoding));
  +        } finally {
  +            IOUtils.shutdownStream(out);
  +        }
       }
   
  -
  -
       /**
  -     * Delete a file. If file is directory delete it and all sub-directories.
  +     * <p>
  +     * Delete a file. If file is a directory, delete it and all sub-directories.
  +     * </p>
  +     * <p>
  +     * The difference between File.delete() and this method are:
  +     * </p>
  +     * <ul>
  +     * <li>A directory to be deleted does not have to be empty.</li>
  +     * <li>You get exceptions when a file or directory cannot be deleted. 
  +     *      (java.io.File methods returns a boolean)</li>
  +     * </ul>
        * @param file file or directory to delete.
        * @throws IOException in case deletion is unsuccessful
        */
  @@ -879,7 +671,7 @@
        * @throws IOException in case deletion is unsuccessful
        */
       private static void deleteDirectoryOnExit(final File directory)
  -        throws IOException {
  +            throws IOException {
           if (!directory.exists()) {
               return;
           }
  @@ -894,7 +686,67 @@
        * @throws IOException in case cleaning is unsuccessful
        */
       private static void cleanDirectoryOnExit(final File directory)
  -        throws IOException {
  +            throws IOException {
  +        if (!directory.exists()) {
  +            final String message = directory + " does not exist";
  +            throw new IllegalArgumentException(message);
  +        }
  +
  +        if (!directory.isDirectory()) {
  +            final String message = directory + " is not a directory";
  +            throw new IllegalArgumentException(message);
  +        }
  +
  +        IOException exception = null;
  +
  +        final File[] files = directory.listFiles();
  +        for (int i = 0; i < files.length; i++) {
  +            final File file = files[i];
  +            try {
  +                forceDeleteOnExit(file);
  +            } catch (final IOException ioe) {
  +                exception = ioe;
  +            }
  +        }
  +
  +        if (null != exception) {
  +            throw exception;
  +        }
  +    }
  +
  +
  +    /**
  +     * Make a directory. If there already exists a file with specified name or
  +     * the directory cannot be created then an exception is thrown.
  +     * @param directory directory to create
  +     * @throws IOException if the directory cannot be created.
  +     */
  +    public static void forceMkdir(final File directory) throws IOException {
  +        if (directory.exists()) {
  +            if (directory.isFile()) {
  +                final String message =
  +                    "File "
  +                        + directory
  +                        + " exists and is "
  +                        + "not a directory. Unable to create directory.";
  +                throw new IOException(message);
  +            }
  +        } else {
  +            if (false == directory.mkdirs()) {
  +                final String message =
  +                    "Unable to create directory " + directory;
  +                throw new IOException(message);
  +            }
  +        }
  +    }
  +
  +    /**
  +     * Recursively count size of a directory (sum of the length of all files).
  +     *
  +     * @param directory directory to inspect
  +     * @return size of directory in bytes.
  +     */
  +    public static long sizeOfDirectory(final File directory) {
           if (!directory.exists()) {
               final String message = directory + " does not exist";
               throw new IllegalArgumentException(message);
  @@ -905,192 +757,513 @@
               throw new IllegalArgumentException(message);
           }
   
  -        IOException exception = null;
  -
  -        final File[] files = directory.listFiles();
  -        for (int i = 0; i < files.length; i++) {
  -            final File file = files[i];
  -            try {
  -                forceDeleteOnExit(file);
  -            } catch (final IOException ioe) {
  -                exception = ioe;
  -            }
  +        long size = 0;
  +
  +        final File[] files = directory.listFiles();
  +        for (int i = 0; i < files.length; i++) {
  +            final File file = files[i];
  +
  +            if (file.isDirectory()) {
  +                size += sizeOfDirectory(file);
  +            } else {
  +                size += file.length();
  +            }
  +        }
  +
  +        return size;
  +    }
  +   
  +     /**
  +      * Tests if the specified <code>File</code> is newer than the reference 
  +      * <code>File</code>.
  +      *
  +      * @param file the <code>File</code> of which the modification date must be compared
  +      * @param reference the <code>File</code> of which the modification date is used 
  +      * like reference
  +      * @return true if the <code>File</code> exists and has been modified more recently
  +      * than the reference <code>File</code>.
  +      */
  +     public static boolean isFileNewer(final File file, final File reference) {
  +         if (reference == null) {
  +             throw new IllegalArgumentException("No specified reference file");
  +         }
  +         if (!reference.exists()) {
  +             throw new IllegalArgumentException("The reference file '" + file + "' doesn't exist");
  +         }
  + 
  +         return isFileNewer(file, reference.lastModified());
  +     }
  + 
  +     /**
  +      * Tests if the specified <code>File</code> is newer than the specified 
  +      * <code>Date</code>
  +      *
  +      * @param file the <code>File</code> of which the modification date must be compared
  +      * @param date the date reference
  +      * @return true if the <code>File</code> exists and has been modified after
  +      * the given <code>Date</code>.
  +      */
  +     public static boolean isFileNewer(final File file, final Date date) {
  +         if (date == null) {
  +             throw new IllegalArgumentException("No specified date");
  +         }
  +         return isFileNewer(file, date.getTime());
  +     }
  + 
  +     /**
  +      * Tests if the specified <code>File</code> is newer than the specified 
  +      * time reference.
  +      *
  +      * @param file the <code>File</code> of which the modification date must be compared.
  +      * @param timeMillis the time reference measured in milliseconds since the epoch 
  +      * (00:00:00 GMT, January 1, 1970)
  +      * @return true if the <code>File</code> exists and has been modified after
  +      * the given time reference.
  +      */
  +     public static boolean isFileNewer(final File file, final long timeMillis) {
  +         if (file == null) {
  +             throw new IllegalArgumentException("No specified file");
  +         }
  +         if (!file.exists()) {
  +             return false;
  +         }
  + 
  +         return file.lastModified() > timeMillis;
  +    }
  +
  +
  +    /* =========================================================================
  +     * Methods below here have not yet been cleaned up
  +     * =========================================================================
  +     */
  +
  +
  +    /**
  +     * Check if a file exits.
  +     *
  +     * @param fileName The name of the file to check.
  +     * @return true if file exists.
  +     */
  +    public static boolean fileExists(String fileName) {
  +        File file = new File(fileName);
  +        return file.exists();
  +    }
  +
  +
  +
  +    /**
  +     * Deletes a file.
  +     *
  +     * @param fileName The name of the file to delete.
  +     */
  +    public static void fileDelete(String fileName) {
  +        File file = new File(fileName);
  +        file.delete();
  +    }
  +
  +    /**
  +     * Given a directory and an array of extensions... return an array of
  +     * compliant files.
  +     *
  +     * TODO Should an ignore list be passed in?
  +     * TODO Should a recurse flag be passed in?
  +     * TODO Should be rewritten using the filefilter package.
  +     * TODO Remove this method before 1.0. listFiles() variants are more flexible.
  +     *
  +     * The given extensions should be like "java" and not like ".java"
  +     * @deprecated Method is too specific. Use one of the listFiles() methods 
  +     * instead. Method will be deleted before Commons IO 1.0.
  +     */
  +    public static String[] getFilesFromExtension(
  +            String directory,
  +            String[] extensions) {
  +
  +        Collection files = new ArrayList();
  +
  +        File currentDir = new File(directory);
  +
  +        String[] unknownFiles = currentDir.list();
  +
  +        if (unknownFiles == null) {
  +            return new String[0];
  +        }
  +
  +        for (int i = 0; i < unknownFiles.length; ++i) {
  +            String currentFileName =
  +                directory
  +                    + System.getProperty("file.separator")
  +                    + unknownFiles[i];
  +            File currentFile = new java.io.File(currentFileName);
  +
  +            if (currentFile.isDirectory()) {
  +
  +                //ignore all CVS directories...
  +                if (currentFile.getName().equals("CVS")) {
  +                    continue;
  +                }
  +
  +                //ok... transverse into this directory and get all the files... then combine
  +                //them with the current list.
  +
  +                String[] fetchFiles =
  +                    getFilesFromExtension(currentFileName, extensions);
  +                files = blendFiles(files, fetchFiles);
  +
  +            } else {
  +                //ok... add the file
  +
  +                String add = currentFile.getAbsolutePath();
  +                if (isValidFile(add, extensions)) {
  +                    files.add(add);
  +
  +                }
  +
  +            }
  +        }
  +
  +        //ok... move the Vector into the files list...
  +
  +        String[] foundFiles = new String[files.size()];
  +        files.toArray(foundFiles);
  +
  +        return foundFiles;
  +
  +    }
  +
  +    /**
  +     * Private hepler method for getFilesFromExtension()
  +     */
  +    private static Collection blendFiles(Collection c, String[] files) {
  +
  +        for (int i = 0; i < files.length; ++i) {
  +            c.add(files[i]);
  +        }
  +
  +        return c;
  +    }
  +
  +    /**
  +     * Checks to see if a file is of a particular type(s).
  +     * Note that if the file does not have an extension, an empty string
  +     * (&quot;&quot;) is matched for.
  +     *
  +     */
  +    private static boolean isValidFile(String file, String[] extensions) {
  +
  +        String extension = extension(file);
  +        if (extension == null) {
  +            extension = "";
  +        }
  +
  +        //ok.. now that we have the "extension" go through the current know
  +        //excepted extensions and determine if this one is OK.
  +
  +        for (int i = 0; i < extensions.length; ++i) {
  +            if (extensions[i].equals(extension))
  +                return true;
  +        }
  +
  +        return false;
  +
  +    }
  +
  +    /**
  +     * Simple way to make a directory. It also creates the parent directories
  +     * if necessary.
  +     * @param dir directory to create
  +     */
  +    public static void mkdir(String dir) {
  +        File file = new File(dir);
  +        if (!file.exists()) {
  +            file.mkdirs();
  +        }
  +    }
  +
  +    /* *** AVALON CODE *** */
  +
  +    /**
  +     * Remove extension from filename.
  +     * ie
  +     * <pre>
  +     * foo.txt    --> foo
  +     * a\b\c.jpg --> a\b\c
  +     * a\b\c     --> a\b\c
  +     * </pre>
  +     *
  +     * @param filename the filename
  +     * @return the filename minus extension
  +     */
  +    public static String removeExtension(final String filename) {
  +        final int index = filename.lastIndexOf('.');
  +
  +        if (-1 == index) {
  +            return filename;
  +        } else {
  +            return filename.substring(0, index);
  +        }
  +    }
  +
  +    /**
  +     * Get extension from filename.
  +     * ie
  +     * <pre>
  +     * foo.txt    --> "txt"
  +     * a\b\c.jpg --> "jpg"
  +     * a\b\c     --> ""
  +     * </pre>
  +     *
  +     * @param filename the filename
  +     * @return the extension of filename or "" if none
  +     */
  +    public static String getExtension(final String filename) {
  +        final int index = filename.lastIndexOf('.');
  +
  +        if (-1 == index) {
  +            return "";
  +        } else {
  +            return filename.substring(index + 1);
  +        }
  +    }
  +
  +    /**
  +     * Remove path from filename. Equivalent to the unix command <code>basename</code>
  +     * ie.
  +     * <pre>
  +     * a/b/c.txt --> c.txt
  +     * a.txt     --> a.txt
  +     * </pre>
  +     *
  +     * @param filepath the filepath
  +     * @return the filename minus path
  +     */
  +    public static String removePath(final String filepath) {
  +        return removePath(filepath, File.separatorChar);
  +    }
  +
  +    /**
  +     * Remove path from filename.
  +     * ie.
  +     * <pre>
  +     * a/b/c.txt --> c.txt
  +     * a.txt     --> a.txt
  +     * </pre>
  +     *
  +     * @param filepath the filepath
  +     * @param fileSeparatorChar the file separator character to use
  +     * @return the filename minus path
  +     */
  +    public static String removePath(
  +        final String filepath,
  +        final char fileSeparatorChar) {
  +        final int index = filepath.lastIndexOf(fileSeparatorChar);
  +
  +        if (-1 == index) {
  +            return filepath;
  +        } else {
  +            return filepath.substring(index + 1);
  +        }
  +    }
  +
  +    /**
  +     * Get path from filename. Roughly equivalent to the unix command <code>dirname</code>.
  +     * ie.
  +     * <pre>
  +     * a/b/c.txt --> a/b
  +     * a.txt     --> ""
  +     * </pre>
  +     *
  +     * @param filepath the filepath
  +     * @return the filename minus path
  +     */
  +    public static String getPath(final String filepath) {
  +        return getPath(filepath, File.separatorChar);
  +    }
  +
  +    /**
  +     * Get path from filename.
  +     * ie.
  +     * <pre>
  +     * a/b/c.txt --> a/b
  +     * a.txt     --> ""
  +     * </pre>
  +     *
  +     * @param filepath the filepath
  +     * @param fileSeparatorChar the file separator character to use
  +     * @return the filename minus path
  +     */
  +    public static String getPath(
  +        final String filepath,
  +        final char fileSeparatorChar) {
  +        final int index = filepath.lastIndexOf(fileSeparatorChar);
  +        if (-1 == index) {
  +            return "";
  +        } else {
  +            return filepath.substring(0, index);
  +        }
  +    }
  +
  +
  +
  +    /**
  +     * Normalize a path.
  +     * Eliminates "/../" and "/./" in a string. Returns <code>null</code> if the ..'s went past the
  +     * root.
  +     * Eg:
  +     * <pre>
  +     * /foo//               -->     /foo/
  +     * /foo/./              -->     /foo/
  +     * /foo/../bar          -->     /bar
  +     * /foo/../bar/         -->     /bar/
  +     * /foo/../bar/../baz   -->     /baz
  +     * //foo//./bar         -->     /foo/bar
  +     * /../                 -->     null
  +     * </pre>
  +     *
  +     * @param path the path to normalize
  +     * @return the normalized String, or <code>null</code> if too many ..'s.
  +     */
  +    public static String normalize(final String path) {
  +        String normalized = path;
  +        // Resolve occurrences of "//" in the normalized path
  +        while (true) {
  +            int index = normalized.indexOf("//");
  +            if (index < 0)
  +                break;
  +            normalized =
  +                normalized.substring(0, index)
  +                    + normalized.substring(index + 1);
  +        }
  +
  +        // Resolve occurrences of "/./" in the normalized path
  +        while (true) {
  +            int index = normalized.indexOf("/./");
  +            if (index < 0)
  +                break;
  +            normalized =
  +                normalized.substring(0, index)
  +                    + normalized.substring(index + 2);
           }
   
  -        if (null != exception) {
  -            throw exception;
  +        // Resolve occurrences of "/../" in the normalized path
  +        while (true) {
  +            int index = normalized.indexOf("/../");
  +            if (index < 0)
  +                break;
  +            if (index == 0)
  +                return null; // Trying to go outside our context
  +            int index2 = normalized.lastIndexOf('/', index - 1);
  +            normalized =
  +                normalized.substring(0, index2)
  +                    + normalized.substring(index + 3);
           }
  +
  +        // Return the normalized path that we have completed
  +        return normalized;
       }
   
       /**
  -     * Make a directory. If there already exists a file with specified name or
  -     * the directory cannot be created then an exception is thrown.
  -     * @param directory directory to create
  -     * @throws IOException if the directory cannot be created.
  +     * Will concatenate 2 paths.  Paths with <code>..</code> will be
  +     * properly handled.
  +     * <p>Eg.,<br />
  +     * <code>/a/b/c</code> + <code>d</code> = <code>/a/b/d</code><br />
  +     * <code>/a/b/c</code> + <code>../d</code> = <code>/a/d</code><br />
  +     * </p>
  +     *
  +     * Thieved from Tomcat sources...
  +     *
  +     * @return The concatenated paths, or null if error occurs
        */
  -    public static void forceMkdir(final File directory) throws IOException {
  -        if (directory.exists()) {
  -            if (directory.isFile()) {
  -                final String message =
  -                    "File "
  -                        + directory
  -                        + " exists and is "
  -                        + "not a directory. Unable to create directory.";
  -                throw new IOException(message);
  -            }
  -        } else {
  -            if (false == directory.mkdirs()) {
  -                final String message =
  -                    "Unable to create directory " + directory;
  -                throw new IOException(message);
  +    public static String catPath(final String lookupPath, final String path) {
  +        // Cut off the last slash and everything beyond
  +        int index = lookupPath.lastIndexOf("/");
  +        String lookup = lookupPath.substring(0, index);
  +        String pth = path;
  +
  +        // Deal with .. by chopping dirs off the lookup path
  +        while (pth.startsWith("../")) {
  +            if (lookup.length() > 0) {
  +                index = lookup.lastIndexOf("/");
  +                lookup = lookup.substring(0, index);
  +            } else {
  +                // More ..'s than dirs, return null
  +                return null;
               }
  -        }
  -    }
   
  -    /**
  -     * Recursively delete a directory.
  -     * @param directory directory to delete
  -     * @throws IOException in case deletion is unsuccessful
  -     */
  -    public static void deleteDirectory(final File directory)
  -        throws IOException {
  -        if (!directory.exists()) {
  -            return;
  +            index = pth.indexOf("../") + 3;
  +            pth = pth.substring(index);
           }
   
  -        cleanDirectory(directory);
  -        if (!directory.delete()) {
  -            final String message =
  -                "Directory " + directory + " unable to be deleted.";
  -            throw new IOException(message);
  -        }
  +        return new StringBuffer(lookup).append("/").append(pth).toString();
       }
   
       /**
  -     * Clean a directory without deleting it.
  -     * @param directory directory to clean
  -     * @throws IOException in case cleaning is unsuccessful
  +     * Resolve a file <code>filename</code> to it's canonical form. If <code>filename</code> is
  +     * relative (doesn't start with <code>/</code>), it will be resolved relative to
  +     * <code>baseFile</code>, otherwise it is treated as a normal root-relative path.
  +     *
  +     * @param baseFile Where to resolve <code>filename</code> from, if <code>filename</code> is
  +     * relative.
  +     * @param filename Absolute or relative file path to resolve.
  +     * @return The canonical <code>File</code> of <code>filename</code>.
        */
  -    public static void cleanDirectory(final File directory)
  -        throws IOException {
  -        if (!directory.exists()) {
  -            final String message = directory + " does not exist";
  -            throw new IllegalArgumentException(message);
  +    public static File resolveFile(final File baseFile, String filename) {
  +        String filenm = filename;
  +        if ('/' != File.separatorChar) {
  +            filenm = filename.replace('/', File.separatorChar);
           }
   
  -        if (!directory.isDirectory()) {
  -            final String message = directory + " is not a directory";
  -            throw new IllegalArgumentException(message);
  +        if ('\\' != File.separatorChar) {
  +            filenm = filename.replace('\\', File.separatorChar);
           }
   
  -        IOException exception = null;
  +        // deal with absolute files
  +        if (filenm.startsWith(File.separator)) {
  +            File file = new File(filenm);
   
  -        final File[] files = directory.listFiles();
  -        for (int i = 0; i < files.length; i++) {
  -            final File file = files[i];
               try {
  -                forceDelete(file);
  -            } catch (final IOException ioe) {
  -                exception = ioe;
  -            }
  -        }
  +                file = file.getCanonicalFile();
  +            } catch (final IOException ioe) {}
   
  -        if (null != exception) {
  -            throw exception;
  +            return file;
           }
  -    }
  +        // FIXME: I'm almost certain this // removal is unnecessary, as getAbsoluteFile() strips
  +        // them. However, I'm not sure about this UNC stuff. (JT)
  +        final char[] chars = filename.toCharArray();
  +        final StringBuffer sb = new StringBuffer();
   
  -    /**
  -     * Recursively count size of a directory (sum of the length of all files).
  -     *
  -     * @param directory directory to inspect
  -     * @return size of directory in bytes.
  -     */
  -    public static long sizeOfDirectory(final File directory) {
  -        if (!directory.exists()) {
  -            final String message = directory + " does not exist";
  -            throw new IllegalArgumentException(message);
  +        //remove duplicate file separators in succession - except
  +        //on win32 at start of filename as UNC filenames can
  +        //be \\AComputer\AShare\myfile.txt
  +        int start = 0;
  +        if ('\\' == File.separatorChar) {
  +            sb.append(filenm.charAt(0));
  +            start++;
           }
   
  -        if (!directory.isDirectory()) {
  -            final String message = directory + " is not a directory";
  -            throw new IllegalArgumentException(message);
  +        for (int i = start; i < chars.length; i++) {
  +            final boolean doubleSeparator =
  +                File.separatorChar == chars[i]
  +                    && File.separatorChar == chars[i - 1];
  +
  +            if (!doubleSeparator) {
  +                sb.append(chars[i]);
  +            }
           }
   
  -        long size = 0;
  +        filenm = sb.toString();
   
  -        final File[] files = directory.listFiles();
  -        for (int i = 0; i < files.length; i++) {
  -            final File file = files[i];
  +        //must be relative
  +        File file = (new File(baseFile, filenm)).getAbsoluteFile();
   
  -            if (file.isDirectory()) {
  -                size += sizeOfDirectory(file);
  -            } else {
  -                size += file.length();
  -            }
  -        }
  +        try {
  +            file = file.getCanonicalFile();
  +        } catch (final IOException ioe) {}
   
  -        return size;
  -    }
  -   
  -     /**
  -      * Tests if the specified <code>File</code> is newer than the reference 
  -      * <code>File</code>.
  -      *
  -      * @param file the <code>File</code> of which the modification date must be compared
  -      * @param reference the <code>File</code> of which the modification date is used 
  -      * like reference
  -      * @return true if the <code>File</code> exists and has been modified more recently
  -      * than the reference <code>File</code>.
  -      */
  -     public static boolean isFileNewer(final File file, final File reference) {
  -         if (reference == null) {
  -             throw new IllegalArgumentException("No specified reference file");
  -         }
  -         if (!reference.exists()) {
  -             throw new IllegalArgumentException("The reference file '" + file + "' doesn't exist");
  -         }
  - 
  -         return isFileNewer(file, reference.lastModified());
  -     }
  - 
  -     /**
  -      * Tests if the specified <code>File</code> is newer than the specified 
  -      * <code>Date</code>
  -      *
  -      * @param file the <code>File</code> of which the modification date must be compared
  -      * @param date the date reference
  -      * @return true if the <code>File</code> exists and has been modified after
  -      * the given <code>Date</code>.
  -      */
  -     public static boolean isFileNewer(final File file, final Date date) {
  -         if (date == null) {
  -             throw new IllegalArgumentException("No specified date");
  -         }
  -         return isFileNewer(file, date.getTime());
  -     }
  - 
  -     /**
  -      * Tests if the specified <code>File</code> is newer than the specified 
  -      * time reference.
  -      *
  -      * @param file the <code>File</code> of which the modification date must be compared.
  -      * @param timeMillis the time reference measured in milliseconds since the epoch 
  -      * (00:00:00 GMT, January 1, 1970)
  -      * @return true if the <code>File</code> exists and has been modified after
  -      * the given time reference.
  -      */
  -     public static boolean isFileNewer(final File file, final long timeMillis) {
  -         if (file == null) {
  -             throw new IllegalArgumentException("No specified file");
  -         }
  -         if (!file.exists()) {
  -             return false;
  -         }
  - 
  -         return file.lastModified() > timeMillis;
  +        return file;
       }
   
  +
  +
       // ----------------------------------------------------------------
       // Deprecated methods
       // ----------------------------------------------------------------
  @@ -1243,24 +1416,6 @@
           } else {
               return "";
           }
  -    }
  -
  -    /**
  -     * Copy a file. The new file will be created if it does not exist. This is
  -     * an inefficient method, which just calls {@link #fileRead(String)} and
  -     * then {@link #fileWrite(String,String)}
  -     *
  -     * @param inFileName the file to copy
  -     * @param outFileName the file to copy to
  -     * @throws Exception if fileRead or fileWrite throw it
  -     * @deprecated This method will be deleted.
  -     *
  -     * TODO This method is not a good idea. It doesn't do a binary copy. DELETE.
  -     */
  -    public static void fileCopy(String inFileName, String outFileName)
  -        throws Exception {
  -        String content = fileRead(inFileName);
  -        fileWrite(outFileName, content);
       }
   
       /**
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org