Skip to content

Commit

Permalink
IO-105 - Add a FileUtils copyDirectory method that makes use of FileF…
Browse files Browse the repository at this point in the history
…ilter

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/io/trunk@609471 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
Niall Pemberton committed Jan 6, 2008
1 parent 6ff368e commit 7cbb276
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 6 deletions.
1 change: 1 addition & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Bug fixes from 1.3.2
- forceDelete of orphaned Softlinks does not work [IO-147]
- Infinite loop on FileUtils.copyDirectory when the destination directory is within
the source directory [IO-141]
- Add a copyDirectory() method that makes use of FileFilter [IO-105]

- HexDump
- HexDump's use of static StringBuffers isn't thread-safe [IO-136]
Expand Down
102 changes: 96 additions & 6 deletions src/java/org/apache/commons/io/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,95 @@ public static void copyDirectory(File srcDir, File destDir) throws IOException {
*/
public static void copyDirectory(File srcDir, File destDir,
boolean preserveFileDate) throws IOException {
copyDirectory(srcDir, destDir, null, preserveFileDate);
}

/**
* Filtered Copy of a directory to a new location preserving the file dates.
* <p>
* This method copies the contents of the specified source directory
* to within the specified destination directory.
* <p>
* 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.
*
* <h4>Example: Copy directories only</h4>
* <pre>
* // only copy the directory structure
* FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY);
* </pre>
*
* <h4>Example: Copy directories and txt files</h4>
* <pre>
* // Create a filter for ".txt" files
* IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
* IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
*
* // Create a filter for either directories or ".txt" files
* FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
*
* // Copy using the filter
* FileUtils.copyDirectory(srcDir, destDir, filter);
* </pre>
*
* @param srcDir an existing directory to copy, must not be <code>null</code>
* @param destDir the new directory, must not be <code>null</code>
* @param filter the filter to apply, null means copy all directories and files
* should be the same as the original
*
* @throws NullPointerException if source or destination is <code>null</code>
* @throws IOException if source or destination is invalid
* @throws IOException if an IO error occurs during copying
* @since Commons IO 1.4
*/
public static void copyDirectory(File srcDir, File destDir,
FileFilter filter) throws IOException {
copyDirectory(srcDir, destDir, filter, true);
}

/**
* Filtered Copy of a directory to a new location.
* <p>
* This method copies the contents of the specified source directory
* to within the specified destination directory.
* <p>
* 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.
*
* <h4>Example: Copy directories only</h4>
* <pre>
* // only copy the directory structure
* FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false);
* </pre>
*
* <h4>Example: Copy directories and txt files</h4>
* <pre>
* // Create a filter for ".txt" files
* IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
* IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
*
* // Create a filter for either directories or ".txt" files
* FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
*
* // Copy using the filter
* FileUtils.copyDirectory(srcDir, destDir, filter, false);
* </pre>
*
* @param srcDir an existing directory to copy, must not be <code>null</code>
* @param destDir the new directory, must not be <code>null</code>
* @param filter the filter to apply, null means copy all directories and files
* @param preserveFileDate true if the file date of the copy
* should be the same as the original
*
* @throws NullPointerException if source or destination is <code>null</code>
* @throws IOException if source or destination is invalid
* @throws IOException if an IO error occurs during copying
* @since Commons IO 1.4
*/
public static void copyDirectory(File srcDir, File destDir,
FileFilter filter, boolean preserveFileDate) throws IOException {
if (srcDir == null) {
throw new NullPointerException("Source must not be null");
}
Expand All @@ -786,7 +875,7 @@ public static void copyDirectory(File srcDir, File destDir,
// Cater for destination being directory within the source directory (see IO-141)
List exclusionList = null;
if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) {
File[] srcFiles = srcDir.listFiles();
File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
if (srcFiles != null && srcFiles.length > 0) {
exclusionList = new ArrayList(srcFiles.length);
for (int i = 0; i < srcFiles.length; i++) {
Expand All @@ -795,21 +884,22 @@ public static void copyDirectory(File srcDir, File destDir,
}
}
}
doCopyDirectory(srcDir, destDir, preserveFileDate, exclusionList);
doCopyDirectory(srcDir, destDir, filter, preserveFileDate, exclusionList);
}

/**
* Internal copy directory method.
*
* @param srcDir the validated source directory, must not be <code>null</code>
* @param destDir the validated destination directory, must not be <code>null</code>
* @param filter the filter to apply, null means copy all directories and files
* @param preserveFileDate whether to preserve the file date
* @param exclusionList List of files and directories to exclude from the copy, may be null
* @throws IOException if an error occurs
* @since Commons IO 1.1
*/
private static void doCopyDirectory(File srcDir, File destDir, boolean preserveFileDate,
List exclusionList) throws IOException {
private static void doCopyDirectory(File srcDir, File destDir, FileFilter filter,
boolean preserveFileDate, List exclusionList) throws IOException {
if (destDir.exists()) {
if (destDir.isDirectory() == false) {
throw new IOException("Destination '" + destDir + "' exists but is not a directory");
Expand All @@ -826,15 +916,15 @@ private static void doCopyDirectory(File srcDir, File destDir, boolean preserveF
throw new IOException("Destination '" + destDir + "' cannot be written to");
}
// recurse
File[] files = srcDir.listFiles();
File[] files = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
if (files == null) { // null if security restricted
throw new IOException("Failed to list contents of " + srcDir);
}
for (int i = 0; i < files.length; i++) {
File copiedFile = new File(destDir, files[i].getName());
if (exclusionList == null || !exclusionList.contains(files[i].getCanonicalPath())) {
if (files[i].isDirectory()) {
doCopyDirectory(files[i], copiedFile, preserveFileDate, exclusionList);
doCopyDirectory(files[i], copiedFile, filter, preserveFileDate, exclusionList);
} else {
doCopyFile(files[i], copiedFile, preserveFileDate);
}
Expand Down
18 changes: 18 additions & 0 deletions src/test/org/apache/commons/io/FileUtilsTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import junit.framework.TestSuite;
import junit.textui.TestRunner;

import org.apache.commons.io.filefilter.NameFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.commons.io.testtools.FileBasedTestCase;

Expand Down Expand Up @@ -738,6 +739,23 @@ public void testCopyDirectoryToExistingDest() throws Exception {
assertEquals(true, new File(destDir, "sub/A.txt").exists());
}

public void testCopyDirectoryFiltered() throws Exception {
File grandParentDir = new File(getTestDirectory(), "grandparent");
File parentDir = new File(grandParentDir, "parent");
File childDir = new File(parentDir, "child");
createFilesForTestCopyDirectory(grandParentDir, parentDir, childDir);

NameFileFilter filter = new NameFileFilter(new String[] {"parent", "child", "file3.txt"});
File destDir = new File(getTestDirectory(), "copydest");

FileUtils.copyDirectory(grandParentDir, destDir, filter);
List files = LIST_WALKER.list(destDir);
assertEquals(3, files.size());
assertEquals("parent", ((File)files.get(0)).getName());
assertEquals("child", ((File)files.get(1)).getName());
assertEquals("file3.txt", ((File)files.get(2)).getName());
}

/** Test for IO-141 */
public void testCopyDirectoryToChild() throws Exception {
File grandParentDir = new File(getTestDirectory(), "grandparent");
Expand Down

0 comments on commit 7cbb276

Please sign in to comment.