This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-io.git
The following commit(s) were added to refs/heads/master by this push: new 1a8fcd01 [IO-811] Files.walk() direct and indirect callers fail to close the returned Stream<Path> 1a8fcd01 is described below commit 1a8fcd01226b7cd547f0e9897d217ef381a94e64 Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Sat Sep 30 08:34:16 2023 -0400 [IO-811] Files.walk() direct and indirect callers fail to close the returned Stream<Path> - Update Javadoc - Release resource in test --- src/main/java/org/apache/commons/io/FileUtils.java | 12 +++-- .../org/apache/commons/io/file/FilesUncheck.java | 60 +++++++++++++++++----- .../java/org/apache/commons/io/file/PathUtils.java | 11 +++- .../apache/commons/io/file/FilesUncheckTest.java | 5 +- 4 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/apache/commons/io/FileUtils.java b/src/main/java/org/apache/commons/io/FileUtils.java index 46275c5f..8a8adca7 100644 --- a/src/main/java/org/apache/commons/io/FileUtils.java +++ b/src/main/java/org/apache/commons/io/FileUtils.java @@ -36,6 +36,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.charset.UnsupportedCharsetException; import java.nio.file.CopyOption; +import java.nio.file.DirectoryStream; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.Files; @@ -2960,13 +2961,16 @@ public class FileUtils { } /** - * Streams over the files in a given directory (and optionally - * its subdirectories) which match an array of extensions. + * Streams over the files in a given directory (and optionally its subdirectories) which match an array of extensions. + * <p> + * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a + * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a + * closed stream causes a {@link IllegalStateException}. + * </p> * * @param directory the directory to search in * @param recursive if true all subdirectories are searched as well - * @param extensions an array of extensions, ex. {"java","xml"}. If this - * parameter is {@code null}, all files are returned. + * @param extensions an array of extensions, ex. {"java","xml"}. If this parameter is {@code null}, all files are returned. * @return an iterator of java.io.File with the matching files * @throws IOException if an I/O error is thrown when accessing the starting file. * @since 2.9.0 diff --git a/src/main/java/org/apache/commons/io/file/FilesUncheck.java b/src/main/java/org/apache/commons/io/file/FilesUncheck.java index 02a1febb..02688cac 100644 --- a/src/main/java/org/apache/commons/io/file/FilesUncheck.java +++ b/src/main/java/org/apache/commons/io/file/FilesUncheck.java @@ -22,6 +22,7 @@ import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.Reader; import java.io.UncheckedIOException; import java.nio.channels.SeekableByteChannel; import java.nio.charset.Charset; @@ -244,6 +245,10 @@ public final class FilesUncheck { /** * Delegates to {@link Files#find(Path, int, BiPredicate, FileVisitOption...)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} wraps a {@link DirectoryStream}. When you require timely disposal of file system resources, use a {@code try}-with-resources + * block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. + * </p> * * @param start See delegate. * @param maxDepth See delegate. @@ -348,6 +353,10 @@ public final class FilesUncheck { /** * Delegates to {@link Files#lines(Path)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} wraps a {@link Reader}. When you require timely disposal of file system resources, use a {@code try}-with-resources block to + * ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. + * </p> * * @param path See delegate. * @return See delegate. @@ -359,6 +368,10 @@ public final class FilesUncheck { /** * Delegates to {@link Files#lines(Path, Charset)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} wraps a {@link Reader}. When you require timely disposal of file system resources, use a {@code try}-with-resources block to + * ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. + * </p> * * @param path See delegate. * @param cs See delegate. @@ -371,6 +384,10 @@ public final class FilesUncheck { /** * Delegates to {@link Files#list(Path)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} wraps a {@link DirectoryStream}. When you require timely disposal of file system resources, use a {@code try}-with-resources + * block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. + * </p> * * @param dir See delegate. * @return See delegate. @@ -474,8 +491,11 @@ public final class FilesUncheck { } /** - * Delegates to {@link Files#newDirectoryStream(Path)} throwing {@link UncheckedIOException} instead of - * {@link IOException}. + * Delegates to {@link Files#newDirectoryStream(Path)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * If you don't use the try-with-resources construct, then you must call the stream's {@link Stream#close()} method after iteration is complete to free any + * resources held for the open directory. + * </p> * * @param dir See delegate. * @return See delegate. @@ -485,10 +505,14 @@ public final class FilesUncheck { } /** - * Delegates to {@link Files#newDirectoryStream(Path, java.nio.file.DirectoryStream.Filter)} throwing - * {@link UncheckedIOException} instead of {@link IOException}. + * Delegates to {@link Files#newDirectoryStream(Path, java.nio.file.DirectoryStream.Filter)} throwing {@link UncheckedIOException} instead of + * {@link IOException}. + * <p> + * If you don't use the try-with-resources construct, then you must call the stream's {@link Stream#close()} method after iteration is complete to free any + * resources held for the open directory. + * </p> * - * @param dir See delegate. + * @param dir See delegate. * @param filter See delegate. * @return See delegate. */ @@ -499,6 +523,10 @@ public final class FilesUncheck { /** * Delegates to {@link Files#newDirectoryStream(Path, String)} throwing {@link UncheckedIOException} instead of * {@link IOException}. + * <p> + * The returned {@link Stream} wraps a {@link DirectoryStream}. When you require timely disposal of file system resources, use a {@code try}-with-resources + * block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. + * </p> * * @param dir See delegate. * @param glob See delegate. @@ -674,10 +702,14 @@ public final class FilesUncheck { } /** - * Delegates to {@link Files#walk(Path, FileVisitOption...)} throwing {@link UncheckedIOException} instead of - * {@link IOException}. + * Delegates to {@link Files#walk(Path, FileVisitOption...)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a + * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a + * closed stream causes a {@link IllegalStateException}. + * </p> * - * @param start See delegate. + * @param start See delegate. * @param options See delegate. * @return See delegate. */ @@ -686,12 +718,16 @@ public final class FilesUncheck { } /** - * Delegates to {@link Files#walk(Path, int, FileVisitOption...)} throwing {@link UncheckedIOException} instead of - * {@link IOException}. + * Delegates to {@link Files#walk(Path, int, FileVisitOption...)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a + * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a + * closed stream causes a {@link IllegalStateException}. + * </p> * - * @param start See delegate. + * @param start See delegate. * @param maxDepth See delegate. - * @param options See delegate. + * @param options See delegate. * @return See delegate. */ public static Stream<Path> walk(final Path start, final int maxDepth, final FileVisitOption... options) { diff --git a/src/main/java/org/apache/commons/io/file/PathUtils.java b/src/main/java/org/apache/commons/io/file/PathUtils.java index 56b2a05c..3cd85f08 100644 --- a/src/main/java/org/apache/commons/io/file/PathUtils.java +++ b/src/main/java/org/apache/commons/io/file/PathUtils.java @@ -1182,8 +1182,12 @@ public final class PathUtils { /** * Creates a new DirectoryStream for Paths rooted at the given directory. + * <p> + * If you don't use the try-with-resources construct, then you must call the stream's {@link Stream#close()} method after iteration is complete to free any + * resources held for the open directory. + * </p> * - * @param dir the path to the directory to stream. + * @param dir the path to the directory to stream. * @param pathFilter the directory stream filter. * @return a new instance. * @throws IOException if an I/O error occurs. @@ -1751,6 +1755,11 @@ public final class PathUtils { /** * Returns a stream of filtered paths. + * <p> + * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a + * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a + * closed stream causes a {@link IllegalStateException}. + * </p> * * @param start the start path * @param pathFilter the path filter diff --git a/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java b/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java index 4fa73681..917de24f 100644 --- a/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java +++ b/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java @@ -50,6 +50,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.apache.commons.io.function.Uncheck; @@ -166,7 +167,9 @@ public class FilesUncheckTest { @Test public void testFind() { - assertNotNull(FilesUncheck.find(FILE_PATH_EMPTY, 0, (t, u) -> false)); + try (Stream<Path> find = FilesUncheck.find(FILE_PATH_EMPTY, 0, (t, u) -> false)) { + assertNotNull(find); + } } @Test