diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index 049dcf906b..bd0f5b5e46 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -427,6 +427,8 @@ Release 2.7.0 - UNRELEASED HADOOP-11248. Add hadoop configuration to disable Azure Filesystem metrics collection. (Shanyu Zhao via cnauroth) + HADOOP-11421. Add IOUtils#listDirectory (cmccabe) + OPTIMIZATIONS HADOOP-11323. WritableComparator#compare keeps reference to byte array. diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/IOUtils.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/IOUtils.java index 6be7446c99..e6c00c940b 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/IOUtils.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/IOUtils.java @@ -23,6 +23,12 @@ import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; +import java.nio.file.DirectoryStream; +import java.nio.file.DirectoryIteratorException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -30,6 +36,7 @@ import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.util.ChunkedArrayList; /** * An utility class for I/O related functionality. @@ -313,4 +320,33 @@ public static void writeFully(FileChannel fc, ByteBuffer buf, offset += fc.write(buf, offset); } while (buf.remaining() > 0); } + + /** + * Return the complete list of files in a directory as strings.

+ * + * This is better than File#listDir because it does not ignore IOExceptions. + * + * @param dir The directory to list. + * @param filter If non-null, the filter to use when listing + * this directory. + * @return The list of files in the directory. + * + * @throws IOException On I/O error + */ + public static List listDirectory(File dir, FilenameFilter filter) + throws IOException { + ArrayList list = new ArrayList (); + try (DirectoryStream stream = + Files.newDirectoryStream(dir.toPath())) { + for (Path entry: stream) { + String fileName = entry.getFileName().toString(); + if ((filter == null) || filter.accept(dir, fileName)) { + list.add(fileName); + } + } + } catch (DirectoryIteratorException e) { + throw e.getCause(); + } + return list; + } } diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestIOUtils.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestIOUtils.java index 5db3c91a48..ac4fb483f6 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestIOUtils.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestIOUtils.java @@ -24,14 +24,21 @@ import java.io.ByteArrayInputStream; import java.io.EOFException; import java.io.File; +import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.apache.commons.io.FileUtils; import org.apache.hadoop.test.GenericTestUtils; +import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; @@ -245,4 +252,41 @@ public void testSkipFully() throws IOException { in.close(); } } + + private static enum NoEntry3Filter implements FilenameFilter { + INSTANCE; + + @Override + public boolean accept(File dir, String name) { + return !name.equals("entry3"); + } + } + + @Test + public void testListDirectory() throws IOException { + File dir = new File("testListDirectory"); + Files.createDirectory(dir.toPath()); + try { + Set entries = new HashSet(); + entries.add("entry1"); + entries.add("entry2"); + entries.add("entry3"); + for (String entry : entries) { + Files.createDirectory(new File(dir, entry).toPath()); + } + List list = IOUtils.listDirectory(dir, + NoEntry3Filter.INSTANCE); + for (String entry : list) { + Assert.assertTrue(entries.remove(entry)); + } + Assert.assertTrue(entries.contains("entry3")); + list = IOUtils.listDirectory(dir, null); + for (String entry : list) { + entries.remove(entry); + } + Assert.assertTrue(entries.isEmpty()); + } finally { + FileUtils.deleteDirectory(dir); + } + } }