You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sc...@apache.org on 2005/02/20 19:13:55 UTC

svn commit: r154553 - in jakarta/commons/proper/io/trunk: project.xml src/java/org/apache/commons/io/FileUtils.java src/test/org/apache/commons/io/FileUtilsTestCase.java

Author: scolebourne
Date: Sun Feb 20 10:13:54 2005
New Revision: 154553

URL: http://svn.apache.org/viewcvs?view=rev&rev=154553
Log:
Add copyDirectory, and refactor copyFile
bug 32944, from Ian Springer

Modified:
    jakarta/commons/proper/io/trunk/project.xml
    jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java
    jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsTestCase.java

Modified: jakarta/commons/proper/io/trunk/project.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/io/trunk/project.xml?view=diff&r1=154552&r2=154553
==============================================================================
--- jakarta/commons/proper/io/trunk/project.xml (original)
+++ jakarta/commons/proper/io/trunk/project.xml Sun Feb 20 10:13:54 2005
@@ -166,6 +166,9 @@
       <email>alban.peignier at free.fr</email>
     </contributor>
     <contributor>
+      <name>Ian Springer</name>
+    </contributor>
+    <contributor>
       <name>Masato Tezuka</name>
     </contributor>
   </contributors>

Modified: jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java?view=diff&r1=154552&r2=154553
==============================================================================
--- jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java (original)
+++ jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java Sun Feb 20 10:13:54 2005
@@ -65,6 +65,7 @@
  * @author Matthew Hawthorne
  * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
  * @author Stephen Colebourne
+ * @author Ian Springer
  * @version $Id$
  */
 public class FileUtils {
@@ -391,111 +392,113 @@
 
     //-----------------------------------------------------------------------
     /**
-     * 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.
-     * The copy will have the same file date as the original.
-     *
-     * @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(
-        File source,
-        File destinationDirectory)
-        throws IOException {
-        if (destinationDirectory.exists()
-            && !destinationDirectory.isDirectory()) {
-            throw new IllegalArgumentException(
-                    "Destination is not a directory");
-        }
-
-        copyFile(source,
-                new File(destinationDirectory, source.getName()), true);
-    }
-
-    /**
-     * 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.
-     * The copy will have the same file date as the original.
-     *
-     * @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).
+     * Copies a file to a directory preserving the file date.
+     * <p>
+     * This method copies the contents of the specified source file
+     * to a file of the same name in the specified destination directory.
+     * The destination directory is created if it does not exist.
+     * If the destination file exists, then this method will overwrite it.
      *
-     * @throws IOException if <code>source</code> does not exist,
-     * <code>destination</code> cannot be written to, or an IO error occurs
-     * during copying.
+     * @param srcFile  an existing file to copy, must not be null
+     * @param destDir  the directory to place the copy in, must not be null
      *
-     * @throws FileNotFoundException if <code>destination</code> is a directory
-     * (use {@link #copyFileToDirectory}).
+     * @throws NullPointerException if source or destination is null
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     * @see #copyFile
      */
-    public static void copyFile(File source, File destination)
-                throws IOException {
-        copyFile(source, destination, true);
+    public static void copyFileToDirectory(File srcFile, File destDir) throws IOException {
+        if (destDir == null) {
+            throw new NullPointerException("Destination must not be null");
+        }
+        if (destDir.exists() && destDir.isDirectory() == false) {
+            throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory");
+        }
+        copyFile(srcFile, new File(destDir, srcFile.getName()), true);
     }
 
-
     /**
-     * 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).
-     * @param preserveFileDate True if the file date of the copy should be the
-     * same as the original.
-     *
-     * @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}).
+     * Copies a file to a new location preserving the file date.
+     * <p>
+     * This method copies the contents of the specified source file to the
+     * specified destination file. The directory holding the destination file is
+     * created if it does not exist. If the destination file exists, then this
+     * method will overwrite it.
+     * 
+     * @param srcFile  an existing file to copy, must not be null
+     * @param destFile  the new file, must not be null
+     * 
+     * @throws NullPointerException if source or destination is null
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     * @see #copyFileToDirectory
      */
-    public static void copyFile(File source, File destination,
-            boolean preserveFileDate)
-            throws IOException {
-        //check source exists
-        if (!source.exists()) {
-            String message = "File " + source + " does not exist";
-            throw new FileNotFoundException(message);
-        }
+    public static void copyFile(File srcFile, File destFile) throws IOException {
+        copyFile(srcFile, destFile, true);
+    }
 
-        //does destinations directory exist ?
-        if (destination.getParentFile() != null
-            && !destination.getParentFile().exists()) {
-            destination.getParentFile().mkdirs();
+    /**
+     * Copies a file to a new location.
+     * <p>
+     * This method copies the contents of the specified source file
+     * to the specified destination file.
+     * The directory holding the destination file is created if it does not exist.
+     * If the destination file exists, then this method will overwrite it.
+     *
+     * @param srcFile  an existing file to copy, must not be null
+     * @param destFile  the new file, must not be null
+     * @param preserveFileDate  true if the file date of the copy
+     *  should be the same as the original
+     *
+     * @throws NullPointerException if source or destination is null
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     * @see #copyFileToDirectory
+     */
+    public static void copyFile(File srcFile, File destFile,
+            boolean preserveFileDate) throws IOException {
+        if (srcFile == null) {
+            throw new NullPointerException("Source must not be null");
+        }
+        if (destFile == null) {
+            throw new NullPointerException("Destination must not be null");
+        }
+        if (srcFile.exists() == false) {
+            throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
+        }
+        if (srcFile.isDirectory()) {
+            throw new IOException("Source '" + srcFile + "' exists but is a directory");
+        }
+        if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {
+            throw new IOException("Source '" + srcFile + "' and destination '" + destFile + "' are the same");
+        }
+        if (destFile.getParentFile() != null && destFile.getParentFile().exists() == false) {
+            if (destFile.getParentFile().mkdirs() == false) {
+                throw new IOException("Destination '" + destFile + "' directory cannot be created");
+            }
         }
-
-        //make sure we can write to destination
-        if (destination.exists() && !destination.canWrite()) {
-            String message =
-                "Unable to open file " + destination + " for writing.";
-            throw new IOException(message);
+        if (destFile.exists() && destFile.canWrite() == false) {
+            throw new IOException("Destination '" + destFile + "' exists but is read-only");
         }
+        doCopyFile(srcFile, destFile, preserveFileDate);
+    }
 
-        //makes sure it is not the same file
-        if (source.getCanonicalPath().equals(destination.getCanonicalPath())) {
-            String message =
-                "Unable to write file " + source + " on itself.";
-            throw new IOException(message);
+    /**
+     * Internal copy file method.
+     * 
+     * @param srcFile  the validated source file, not null
+     * @param destFile  the validated destination file, not null
+     * @param preserveFileDate  whether to preserve the file date
+     * @throws IOException if an error occurs
+     */
+    private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
+        if (destFile.exists() && destFile.isDirectory()) {
+            throw new IOException("Destination '" + destFile + "' exists but is a directory");
         }
 
-        FileInputStream input = new FileInputStream(source);
+        FileInputStream input = new FileInputStream(srcFile);
         try {
-            FileOutputStream output = new FileOutputStream(destination);
+            FileOutputStream output = new FileOutputStream(destFile);
             try {
                 IOUtils.copy(input, output);
             } finally {
@@ -505,21 +508,110 @@
             IOUtils.closeQuietly(input);
         }
 
-        if (source.length() != destination.length()) {
-            String message =
-                "Failed to copy full contents from "
-                    + source
-                    + " to "
-                    + destination;
-            throw new IOException(message);
+        if (srcFile.length() != destFile.length()) {
+            throw new IOException("Failed to copy full contents from '" +
+                    srcFile + "' to '" + destFile + "'");
         }
-
         if (preserveFileDate) {
-            //file copy should preserve file date
-            destination.setLastModified(source.lastModified());
+            destFile.setLastModified(srcFile.lastModified());
         }
     }
 
+    //-----------------------------------------------------------------------
+    /**
+     * Copies a whole directory to a new location preserving the file dates.
+     * <p>
+     * This method copies the specified directory and all its child
+     * directories and files to the specified destination.
+     * The destination is the new location and name of the directory.
+     * If it already exists, the contents will be overwritten.
+     *
+     * @param srcDir  an existing directory to copy, must not be null
+     * @param destDir  the new directory, must not be null
+     *
+     * @throws NullPointerException if source or destination is null
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     */
+    public static void copyDirectory(File srcDir, File destDir) throws IOException {
+        copyDirectory(srcDir, destDir, true);
+    }
+
+    /**
+     * Copies a whole directory to a new location.
+     * <p>
+     * This method copies the contents of the specified source directory
+     * to within the specified destination directory.
+     * The destination directory is created if it does not exist.
+     * If the destination directory did exist, then this method merges
+     * the source with the destination, with the source taking precedence.
+     *
+     * @param srcDir  an existing directory to copy, must not be null
+     * @param destDir  the new directory, must not be null
+     * @param preserveFileDate  true if the file date of the copy
+     *  should be the same as the original
+     *
+     * @throws NullPointerException if source or destination is null
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     */
+    public static void copyDirectory(File srcDir, File destDir,
+            boolean preserveFileDate) throws IOException {
+        if (srcDir == null) {
+            throw new NullPointerException("Source must not be null");
+        }
+        if (destDir == null) {
+            throw new NullPointerException("Destination must not be null");
+        }
+        if (srcDir.exists() == false) {
+            throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
+        }
+        if (srcDir.isDirectory() == false) {
+            throw new IOException("Source '" + srcDir + "' exists but is not a directory");
+        }
+        if (srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) {
+            throw new IOException("Source '" + srcDir + "' and destination '" + destDir + "' are the same");
+        }
+        doCopyDirectory(srcDir, destDir, preserveFileDate);
+    }
+
+    /**
+     * Internal copy directory method.
+     * 
+     * @param srcDir  the validated source directory, not null
+     * @param destDir  the validated destination directory, not null
+     * @param preserveFileDate  whether to preserve the file date
+     * @throws IOException if an error occurs
+     */
+    private static void doCopyDirectory(File srcDir, File destDir, boolean preserveFileDate) throws IOException {
+        if (destDir.exists()) {
+            if (destDir.isDirectory() == false) {
+                throw new IOException("Destination '" + destDir + "' exists but is not a directory");
+            }
+        } else {
+            if (destDir.mkdirs() == false) {
+                throw new IOException("Destination '" + destDir + "' directory cannot be created");
+            }
+            if (preserveFileDate) {
+                destDir.setLastModified(srcDir.lastModified());
+            }
+        }
+        if (destDir.canWrite() == false) {
+            throw new IOException("Destination '" + destDir + "' cannot be written to");
+        }
+        // recurse
+        File[] files = srcDir.listFiles();
+        for (int i = 0; i < files.length; i++) {
+            File copiedFile = new File(destDir, files[i].getName());
+            if (files[i].isDirectory()) {
+                doCopyDirectory(files[i], copiedFile, preserveFileDate);
+            } else {
+                doCopyFile(files[i], copiedFile, preserveFileDate);
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
     /**
      * Copies bytes from the URL <code>source</code> to a file
      * <code>destination</code>. The directories up to <code>destination</code>
@@ -565,7 +657,7 @@
         }
     }
 
-
+    //-----------------------------------------------------------------------
     /**
      * Recursively delete a directory.
      * @param directory directory to delete

Modified: jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsTestCase.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsTestCase.java?view=diff&r1=154552&r2=154553
==============================================================================
--- jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsTestCase.java (original)
+++ jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsTestCase.java Sun Feb 20 10:13:54 2005
@@ -405,6 +405,74 @@
             testFile1.lastModified() != destination.lastModified());*/    
     }
 
+    public void testCopyDirectoryToNonExistingDest() throws Exception {
+        createFile(testFile1, 1234);
+        createFile(testFile2, 4321);
+        File srcDir = getTestDirectory();
+        File subDir = new File(srcDir, "sub");
+        subDir.mkdir();
+        File subFile = new File(subDir, "A.txt");
+        FileUtils.writeStringToFile(subFile, "HELLO WORLD", "UTF8");
+        File destDir = new File(System.getProperty("java.io.tmpdir"), "tmp-FileUtilsTestCase");
+        FileUtils.deleteDirectory(destDir);
+        
+        FileUtils.copyDirectory(srcDir, destDir);
+        
+        assertTrue("Check exists", destDir.exists());
+        assertEquals("Check size", FileUtils.sizeOfDirectory(srcDir), FileUtils.sizeOfDirectory(destDir));
+        assertEquals(true, new File(destDir, "sub/A.txt").exists());
+        FileUtils.deleteDirectory(destDir);
+    }
+
+    public void testCopyDirectoryToExistingDest() throws Exception {
+        createFile(testFile1, 1234);
+        createFile(testFile2, 4321);
+        File srcDir = getTestDirectory();
+        File subDir = new File(srcDir, "sub");
+        subDir.mkdir();
+        File subFile = new File(subDir, "A.txt");
+        FileUtils.writeStringToFile(subFile, "HELLO WORLD", "UTF8");
+        File destDir = new File(System.getProperty("java.io.tmpdir"), "tmp-FileUtilsTestCase");
+        FileUtils.deleteDirectory(destDir);
+        destDir.mkdirs();
+        
+        FileUtils.copyDirectory(srcDir, destDir);
+        
+        assertEquals(FileUtils.sizeOfDirectory(srcDir), FileUtils.sizeOfDirectory(destDir));
+        assertEquals(true, new File(destDir, "sub/A.txt").exists());
+    }
+
+    public void testCopyDirectoryErrors() throws Exception {
+        try {
+            FileUtils.copyDirectory(null, null);
+            fail();
+        } catch (NullPointerException ex) {}
+        try {
+            FileUtils.copyDirectory(new File("a"), null);
+            fail();
+        } catch (NullPointerException ex) {}
+        try {
+            FileUtils.copyDirectory(null, new File("a"));
+            fail();
+        } catch (NullPointerException ex) {}
+        try {
+            FileUtils.copyDirectory(new File("doesnt-exist"), new File("a"));
+            fail();
+        } catch (IOException ex) {}
+        try {
+            FileUtils.copyDirectory(testFile1, new File("a"));
+            fail();
+        } catch (IOException ex) {}
+        try {
+            FileUtils.copyDirectory(getTestDirectory(), testFile1);
+            fail();
+        } catch (IOException ex) {}
+        try {
+            FileUtils.copyDirectory(getTestDirectory(), getTestDirectory());
+            fail();
+        } catch (IOException ex) {}
+    }
+
     // forceDelete
 
     public void testForceDeleteAFile1() throws Exception {



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