diff options
Diffstat (limited to 'src/main')
36 files changed, 739 insertions, 217 deletions
diff --git a/src/main/java/org/apache/commons/io/ByteOrderMark.java b/src/main/java/org/apache/commons/io/ByteOrderMark.java index 2e4f0305..c5ab57b1 100644 --- a/src/main/java/org/apache/commons/io/ByteOrderMark.java +++ b/src/main/java/org/apache/commons/io/ByteOrderMark.java @@ -115,7 +115,14 @@ public class ByteOrderMark implements Serializable { */ public static final char UTF_BOM = '\uFEFF'; + /** + * Charset name. + */ private final String charsetName; + + /** + * Bytes. + */ private final int[] bytes; /** diff --git a/src/main/java/org/apache/commons/io/CopyUtils.java b/src/main/java/org/apache/commons/io/CopyUtils.java index b7e7829e..da01a987 100644 --- a/src/main/java/org/apache/commons/io/CopyUtils.java +++ b/src/main/java/org/apache/commons/io/CopyUtils.java @@ -103,7 +103,7 @@ import java.nio.charset.Charset; * method variants to specify the encoding, each row may * correspond to up to 2 methods. * <p> - * Origin of code: Excalibur. + * Provenance: Excalibur. * * @deprecated Use IOUtils. Will be removed in 3.0. * Methods renamed to IOUtils.write() or IOUtils.copy(). diff --git a/src/main/java/org/apache/commons/io/EndianUtils.java b/src/main/java/org/apache/commons/io/EndianUtils.java index acc95319..83c2ce25 100644 --- a/src/main/java/org/apache/commons/io/EndianUtils.java +++ b/src/main/java/org/apache/commons/io/EndianUtils.java @@ -34,7 +34,7 @@ import java.io.OutputStream; * This class helps you solve this incompatibility. * </p> * <p> - * Origin of code: Excalibur + * Provenance: Excalibur * </p> * * @see org.apache.commons.io.input.SwappedDataInputStream diff --git a/src/main/java/org/apache/commons/io/FileUtils.java b/src/main/java/org/apache/commons/io/FileUtils.java index 807dc37c..80d100f1 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; @@ -108,7 +109,7 @@ import org.apache.commons.io.function.Uncheck; * {@link SecurityException} are not documented in the Javadoc. * </p> * <p> - * Origin of code: Excalibur, Alexandria, Commons-Utils + * Provenance: Excalibur, Alexandria, Commons-Utils * </p> */ public class FileUtils { @@ -352,16 +353,13 @@ public class FileUtils { * This method checks to see if the two files are different lengths or if they point to the same file, before * resorting to byte-by-byte comparison of the contents. * </p> - * <p> - * Code origin: Avalon - * </p> * * @param file1 the first file * @param file2 the second file * @return true if the content of the files are equal or they both don't exist, false otherwise * @throws IllegalArgumentException when an input is not a file. * @throws IOException If an I/O error occurs. - * @see org.apache.commons.io.file.PathUtils#fileContentEquals(Path,Path,java.nio.file.LinkOption[],java.nio.file.OpenOption...) + * @see PathUtils#fileContentEquals(Path,Path) */ public static boolean contentEquals(final File file1, final File file2) throws IOException { if (file1 == null && file2 == null) { @@ -393,9 +391,7 @@ public class FileUtils { return true; } - try (InputStream input1 = Files.newInputStream(file1.toPath()); InputStream input2 = Files.newInputStream(file2.toPath())) { - return IOUtils.contentEquals(input1, input2); - } + return PathUtils.fileContentEquals(file1.toPath(), file2.toPath()); } /** @@ -451,12 +447,12 @@ public class FileUtils { } /** - * Converts a Collection containing java.io.File instances into array + * Converts a Collection containing {@link File} instances into array * representation. This is to account for the difference between * File.listFiles() and FileUtils.listFiles(). * - * @param files a Collection containing java.io.File instances - * @return an array of java.io.File + * @param files a Collection containing {@link File} instances + * @return an array of {@link File} */ public static File[] convertFileCollectionToFileArray(final Collection<File> files) { return files.toArray(EMPTY_FILE_ARRAY); @@ -1449,7 +1445,7 @@ public class FileUtils { /** * Returns a {@link File} representing the system temporary directory. * - * @return the system temporary directory. + * @return the system temporary directory as a File * @since 2.0 */ public static File getTempDirectory() { @@ -1459,7 +1455,12 @@ public class FileUtils { /** * Returns the path to the system temporary directory. * - * @return the path to the system temporary directory. + * WARNING: this method relies on the Java system property 'java.io.tmpdir' + * which may or may not have a trailing file separator. + * This can affect code that uses String processing to manipulate pathnames rather + * than the standard libary methods in classes such as {@link java.io.File} + * + * @return the path to the system temporary directory as a String * @since 2.0 */ public static String getTempDirectoryPath() { @@ -1971,7 +1972,7 @@ public class FileUtils { * @param dirFilter optional filter to apply when finding subdirectories. * If this parameter is {@code null}, subdirectories will not be included in the * search. Use TrueFileFilter.INSTANCE to match all directories. - * @return an iterator of java.io.File for the matching files + * @return an iterator of {@link File} for the matching files * @see org.apache.commons.io.filefilter.FileFilterUtils * @see org.apache.commons.io.filefilter.NameFileFilter * @since 1.2 @@ -1988,14 +1989,14 @@ public class FileUtils { * </p> * * @param directory the directory to search in - * @param extensions an array of extensions, ex. {"java","xml"}. If this + * @param extensions an array of extensions, for example, {"java","xml"}. If this * parameter is {@code null}, all files are returned. * @param recursive if true all subdirectories are searched as well - * @return an iterator of java.io.File with the matching files + * @return an iterator of {@link File} with the matching files * @since 1.2 */ public static Iterator<File> iterateFiles(final File directory, final String[] extensions, final boolean recursive) { - return Uncheck.apply(d -> streamFiles(d, recursive, extensions).iterator(), directory); + return StreamIterator.iterator(Uncheck.get(() -> streamFiles(directory, recursive, extensions))); } /** @@ -2016,7 +2017,7 @@ public class FileUtils { * @param dirFilter optional filter to apply when finding subdirectories. * If this parameter is {@code null}, subdirectories will not be included in the * search. Use TrueFileFilter.INSTANCE to match all directories. - * @return an iterator of java.io.File for the matching files + * @return an iterator of {@link File} for the matching files * @see org.apache.commons.io.filefilter.FileFilterUtils * @see org.apache.commons.io.filefilter.NameFileFilter * @since 2.2 @@ -2216,28 +2217,30 @@ public class FileUtils { * @param dirFilter optional filter to apply when finding subdirectories. * If this parameter is {@code null}, subdirectories will not be included in the * search. Use {@link TrueFileFilter#INSTANCE} to match all directories. - * @return a collection of java.io.File with the matching files + * @return a collection of {@link File} with the matching files * @see org.apache.commons.io.filefilter.FileFilterUtils * @see org.apache.commons.io.filefilter.NameFileFilter */ public static Collection<File> listFiles(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { final AccumulatorPathVisitor visitor = Uncheck .apply(d -> listAccumulate(d, FileFileFilter.INSTANCE.and(fileFilter), dirFilter, FileVisitOption.FOLLOW_LINKS), directory); - return visitor.getFileList().stream().map(Path::toFile).collect(Collectors.toList()); + return toList(visitor.getFileList().stream().map(Path::toFile)); } /** - * Finds files within a given directory (and optionally its subdirectories) + * Lists 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 + * @param extensions an array of extensions, for example, {"java","xml"}. If this * parameter is {@code null}, all files are returned. * @param recursive if true all subdirectories are searched as well - * @return a collection of java.io.File with the matching files + * @return a collection of {@link File} with the matching files */ public static Collection<File> listFiles(final File directory, final String[] extensions, final boolean recursive) { - return Uncheck.apply(d -> toList(streamFiles(d, recursive, extensions)), directory); + try (Stream<File> fileStream = Uncheck.get(() -> streamFiles(directory, recursive, extensions))) { + return toList(fileStream); + } } /** @@ -2253,7 +2256,7 @@ public class FileUtils { * @param dirFilter optional filter to apply when finding subdirectories. * If this parameter is {@code null}, subdirectories will not be included in the * search. Use TrueFileFilter.INSTANCE to match all directories. - * @return a collection of java.io.File with the matching files + * @return a collection of {@link File} with the matching files * @see org.apache.commons.io.FileUtils#listFiles * @see org.apache.commons.io.filefilter.FileFilterUtils * @see org.apache.commons.io.filefilter.NameFileFilter @@ -2264,7 +2267,7 @@ public class FileUtils { directory); final List<Path> list = visitor.getFileList(); list.addAll(visitor.getDirList()); - return list.stream().map(Path::toFile).collect(Collectors.toList()); + return toList(list.stream().map(Path::toFile)); } /** @@ -2570,9 +2573,8 @@ public class FileUtils { * @param file the file to read, must not be {@code null} * @return the file contents, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @since 1.1 */ public static byte[] readFileToByteArray(final File file) throws IOException { @@ -2587,9 +2589,8 @@ public class FileUtils { * @param file the file to read, must not be {@code null} * @return the file contents, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @since 1.3.1 * @deprecated 2.5 use {@link #readFileToString(File, Charset)} instead (and specify the appropriate encoding) */ @@ -2606,9 +2607,8 @@ public class FileUtils { * @param charsetName the name of the requested charset, {@code null} means platform default * @return the file contents, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @since 2.3 */ public static String readFileToString(final File file, final Charset charsetName) throws IOException { @@ -2622,9 +2622,8 @@ public class FileUtils { * @param charsetName the name of the requested charset, {@code null} means platform default * @return the file contents, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io * .UnsupportedEncodingException} in version 2.2 if the named charset is unavailable. * @since 2.3 @@ -2640,9 +2639,8 @@ public class FileUtils { * @param file the file to read, must not be {@code null} * @return the list of Strings representing each line in the file, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @since 1.3 * @deprecated 2.5 use {@link #readLines(File, Charset)} instead (and specify the appropriate encoding) */ @@ -2659,9 +2657,8 @@ public class FileUtils { * @param charset the charset to use, {@code null} means platform default * @return the list of Strings representing each line in the file, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @since 2.3 */ public static List<String> readLines(final File file, final Charset charset) throws IOException { @@ -2675,9 +2672,8 @@ public class FileUtils { * @param charsetName the name of the requested charset, {@code null} means platform default * @return the list of Strings representing each line in the file, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io * .UnsupportedEncodingException} in version 2.2 if the named charset is unavailable. * @since 1.1 @@ -2861,9 +2857,8 @@ public class FileUtils { * {@code false} otherwise * @throws NullPointerException if sourceFile is {@code null}. * @throws NullPointerException if targetFile is {@code null}. - * @throws IOException if setting the last-modified time failed. */ - private static boolean setTimes(final File sourceFile, final File targetFile) throws IOException { + private static boolean setTimes(final File sourceFile, final File targetFile) { Objects.requireNonNull(sourceFile, "sourceFile"); Objects.requireNonNull(targetFile, "targetFile"); try { @@ -2967,14 +2962,17 @@ 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. - * @return an iterator of java.io.File with the matching files + * @param extensions an array of extensions, for example, {"java","xml"}. If this parameter is {@code null}, all files are returned. + * @return a Stream of {@link File} for matching files. * @throws IOException if an I/O error is thrown when accessing the starting file. * @since 2.9.0 */ @@ -3006,8 +3004,8 @@ public class FileUtils { if (url == null || !"file".equalsIgnoreCase(url.getProtocol())) { return null; } - final String filename = url.getFile().replace('/', File.separatorChar); - return new File(decodeUrl(filename)); + final String fileName = url.getFile().replace('/', File.separatorChar); + return new File(decodeUrl(fileName)); } /** @@ -3048,6 +3046,15 @@ public class FileUtils { return files; } + /** + * Consumes all of the given stream. + * <p> + * When called from a FileTreeWalker, the walker <em>closes</em> the stream because {@link FileTreeWalker#next()} calls {@code top.stream().close()}. + * </p> + * + * @param stream The stream to consume. + * @return a new List. + */ private static List<File> toList(final Stream<File> stream) { return stream.collect(Collectors.toList()); } diff --git a/src/main/java/org/apache/commons/io/FilenameUtils.java b/src/main/java/org/apache/commons/io/FilenameUtils.java index 09c62f71..049c3a71 100644 --- a/src/main/java/org/apache/commons/io/FilenameUtils.java +++ b/src/main/java/org/apache/commons/io/FilenameUtils.java @@ -90,7 +90,7 @@ import java.util.stream.Stream; * currently running on. * </p> * <p> - * Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils. + * Provenance: Excalibur, Alexandria, Tomcat, Commons-Utils. * </p> * * @since 1.1 @@ -846,7 +846,7 @@ public class FilenameUtils { * ~user --> 6 --> named user (slash added) * //server/a/b/c.txt --> 9 * ///a/b/c.txt --> -1 --> error - * C: --> 0 --> valid filename as only null character and / are reserved characters + * C: --> 0 --> valid file name as only null character and / are reserved characters * </pre> * <p> * The output will be the same irrespective of the machine that the code is running on. diff --git a/src/main/java/org/apache/commons/io/HexDump.java b/src/main/java/org/apache/commons/io/HexDump.java index d7e5abdc..0a53e3d6 100644 --- a/src/main/java/org/apache/commons/io/HexDump.java +++ b/src/main/java/org/apache/commons/io/HexDump.java @@ -31,7 +31,7 @@ import org.apache.commons.io.output.CloseShieldOutputStream; * in hexadecimal form. * </p> * <p> - * Origin of code: POI. + * Provenance: POI. * </p> */ public class HexDump { diff --git a/src/main/java/org/apache/commons/io/IOIndexedException.java b/src/main/java/org/apache/commons/io/IOIndexedException.java index 9a85328e..1893509f 100644 --- a/src/main/java/org/apache/commons/io/IOIndexedException.java +++ b/src/main/java/org/apache/commons/io/IOIndexedException.java @@ -42,6 +42,9 @@ public class IOIndexedException extends IOException { return String.format("%s #%,d: %s", name, index, msg); } + /** + * Index. + */ private final int index; /** diff --git a/src/main/java/org/apache/commons/io/IOUtils.java b/src/main/java/org/apache/commons/io/IOUtils.java index b6b6f137..dfb4c19e 100644 --- a/src/main/java/org/apache/commons/io/IOUtils.java +++ b/src/main/java/org/apache/commons/io/IOUtils.java @@ -45,6 +45,7 @@ import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.Selector; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.Arrays; import java.util.Collection; @@ -118,7 +119,7 @@ import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; * closing streams after use. * </p> * <p> - * Origin of code: Excalibur. + * Provenance: Excalibur. * </p> */ public class IOUtils { @@ -893,7 +894,6 @@ public class IOUtils { * @param input2 the second stream * @return true if the content of the streams are equal or they both don't * exist, false otherwise - * @throws NullPointerException if either input is null * @throws IOException if an I/O error occurs */ public static boolean contentEquals(final InputStream input1, final InputStream input2) throws IOException { @@ -3827,28 +3827,36 @@ public class IOUtils { * Writes the {@link #toString()} value of each item in a collection to * an {@link OutputStream} line by line, using the specified character * encoding and the specified line ending. + * <p> + * UTF-16 is written big-endian with no byte order mark. + * For little endian, use UTF-16LE. For a BOM, write it to the stream + * before calling this method. + * </p> * * @param lines the lines to write, null entries produce blank lines * @param lineEnding the line separator to use, null is system default * @param output the {@link OutputStream} to write to, not null, not closed * @param charset the charset to use, null means platform default - * @throws NullPointerException if the output is null + * @throws NullPointerException if output is null * @throws IOException if an I/O error occurs * @since 2.3 */ public static void writeLines(final Collection<?> lines, String lineEnding, final OutputStream output, - final Charset charset) throws IOException { + Charset charset) throws IOException { if (lines == null) { return; } if (lineEnding == null) { lineEnding = System.lineSeparator(); } - final Charset cs = Charsets.toCharset(charset); - final byte[] eolBytes = lineEnding.getBytes(cs); + if (StandardCharsets.UTF_16.equals(charset)) { + // don't write a BOM + charset = StandardCharsets.UTF_16BE; + } + final byte[] eolBytes = lineEnding.getBytes(charset); for (final Object line : lines) { if (line != null) { - write(line.toString(), output, cs); + write(line.toString(), output, charset); } output.write(eolBytes); } diff --git a/src/main/java/org/apache/commons/io/RandomAccessFileMode.java b/src/main/java/org/apache/commons/io/RandomAccessFileMode.java index 54061588..8b51e439 100644 --- a/src/main/java/org/apache/commons/io/RandomAccessFileMode.java +++ b/src/main/java/org/apache/commons/io/RandomAccessFileMode.java @@ -20,6 +20,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.RandomAccessFile; import java.nio.file.Path; +import java.util.Objects; /** * Access modes and factory methods for {@link RandomAccessFile}. @@ -77,7 +78,7 @@ public enum RandomAccessFileMode { * @throws FileNotFoundException See {@link RandomAccessFile#RandomAccessFile(File, String)}. */ public RandomAccessFile create(final Path file) throws FileNotFoundException { - return create(file.toFile()); + return create(Objects.requireNonNull(file.toFile(), "file")); } /** diff --git a/src/main/java/org/apache/commons/io/RandomAccessFiles.java b/src/main/java/org/apache/commons/io/RandomAccessFiles.java index 2fc071fc..0e0140b6 100644 --- a/src/main/java/org/apache/commons/io/RandomAccessFiles.java +++ b/src/main/java/org/apache/commons/io/RandomAccessFiles.java @@ -19,15 +19,55 @@ package org.apache.commons.io; import java.io.IOException; import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.util.Objects; + +import org.apache.commons.io.channels.FileChannels; /** - * Works on RandomAccessFile. + * Works with {@link RandomAccessFile}. * * @since 2.13.0 */ public class RandomAccessFiles { /** + * Tests if two RandomAccessFile contents are equal. + * + * @param raf1 A RandomAccessFile. + * @param raf2 Another RandomAccessFile. + * @return true if the contents of both RandomAccessFiles are equal, false otherwise. + * @throws IOException if an I/O error occurs. + * @since 2.15.0 + */ + @SuppressWarnings("resource") // See comments + public static boolean contentEquals(final RandomAccessFile raf1, final RandomAccessFile raf2) throws IOException { + // Short-circuit test + if (Objects.equals(raf1, raf2)) { + return true; + } + // Short-circuit test + final long length1 = length(raf1); + final long length2 = length(raf2); + if (length1 != length2) { + return false; + } + if (length1 == 0 && length2 == 0) { + return true; + } + // Dig in and to the work + // We do not close FileChannels because that closes the owning RandomAccessFile. + // Instead, the caller is assumed to manage the given RandomAccessFile objects. + final FileChannel channel1 = raf1.getChannel(); + final FileChannel channel2 = raf2.getChannel(); + return FileChannels.contentEquals(channel1, channel2, IOUtils.DEFAULT_BUFFER_SIZE); + } + + private static long length(final RandomAccessFile raf) throws IOException { + return raf != null ? raf.length() : 0; + } + + /** * Reads a byte array starting at "position" for "length" bytes. * * @param input The source RandomAccessFile. @@ -42,4 +82,17 @@ public class RandomAccessFiles { return IOUtils.toByteArray(input::read, length); } + /** + * Resets the given file to position 0. + * + * @param raf The RandomAccessFile to reset. + * @return The given RandomAccessFile. + * @throws IOException If {@code pos} is less than {@code 0} or if an I/O error occurs. + * @since 2.15.0 + */ + public static RandomAccessFile reset(final RandomAccessFile raf) throws IOException { + raf.seek(0); + return raf; + } + } diff --git a/src/main/java/org/apache/commons/io/StreamIterator.java b/src/main/java/org/apache/commons/io/StreamIterator.java index 3a321681..23465657 100644 --- a/src/main/java/org/apache/commons/io/StreamIterator.java +++ b/src/main/java/org/apache/commons/io/StreamIterator.java @@ -17,42 +17,55 @@ package org.apache.commons.io; -import java.io.Closeable; import java.util.Iterator; import java.util.Objects; import java.util.stream.Stream; /** - * Wraps and presents a stream as a closable iterator resource that automatically closes itself when reaching the end - * of stream. + * Wraps and presents a {@link Stream} as a {@link AutoCloseable} {@link Iterator} resource that automatically closes itself when reaching the end of stream. * - * @param <E> The stream and iterator type. - * @since 2.9.0 + * <h2>Warning</h2> + * <p> + * In order to close the stream, the call site MUST either close the stream it allocated OR call this iterator until the end. + * </p> + * + * @param <E> The {@link Stream} and {@link Iterator} type. + * @since 2.15.0 */ -final class StreamIterator<E> implements Iterator<E>, Closeable { +public final class StreamIterator<E> implements Iterator<E>, AutoCloseable { /** - * Wraps and presents a stream as a closable resource that automatically closes itself when reaching the end of - * stream. - * <h2>Warning</h2> + * Wraps and presents a stream as a closable resource that automatically closes itself when reaching the end of stream. + * <p> + * <b>Warning</b> + * </p> * <p> - * In order to close the stream, the call site MUST either close the stream it allocated OR call the iterator until - * the end. + * In order to close the stream, the call site MUST either close the stream it allocated OR call this iterator until the end. * </p> * - * @param <T> The stream and iterator type. + * @param <T> The stream and iterator type. * @param stream The stream iterate. * @return A new iterator. */ - @SuppressWarnings("resource") // Caller MUST close or iterate to the end. - public static <T> Iterator<T> iterator(final Stream<T> stream) { - return new StreamIterator<>(stream).iterator; + public static <T> StreamIterator<T> iterator(final Stream<T> stream) { + return new StreamIterator<>(stream); } + /** + * The given stream's Iterator. + */ private final Iterator<E> iterator; + /** + * The given stream. + */ private final Stream<E> stream; + /** + * Whether {@link #close()} has been called. + */ + private boolean closed; + private StreamIterator(final Stream<E> stream) { this.stream = Objects.requireNonNull(stream, "stream"); this.iterator = stream.iterator(); @@ -63,11 +76,16 @@ final class StreamIterator<E> implements Iterator<E>, Closeable { */ @Override public void close() { + closed = true; stream.close(); } @Override public boolean hasNext() { + if (closed) { + // Calling Iterator#hasNext() on a closed java.nio.file.FileTreeIterator causes an IllegalStateException. + return false; + } final boolean hasNext = iterator.hasNext(); if (!hasNext) { close(); diff --git a/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java b/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java index d94638ac..e0f9ba66 100644 --- a/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java +++ b/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java @@ -154,6 +154,11 @@ public abstract class AbstractStreamBuilder<T, B extends AbstractStreamBuilder<T return checkOrigin().getInputStream(getOpenOptions()); } + /** + * Gets the OpenOption. + * + * @return the OpenOption. + */ protected OpenOption[] getOpenOptions() { return openOptions; } diff --git a/src/main/java/org/apache/commons/io/channels/FileChannels.java b/src/main/java/org/apache/commons/io/channels/FileChannels.java new file mode 100644 index 00000000..468c85b4 --- /dev/null +++ b/src/main/java/org/apache/commons/io/channels/FileChannels.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.io.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.Objects; + +import org.apache.commons.io.IOUtils; + +/** + * Works with {@link FileChannel}. + * + * @since 2.15.0 + */ +public final class FileChannels { + + /** + * Tests if two RandomAccessFiles contents are equal. + * + * @param channel1 A FileChannel. + * @param channel2 Another FileChannel. + * @param byteBufferSize The two internal buffer capacities, in bytes. + * @return true if the contents of both RandomAccessFiles are equal, false otherwise. + * @throws IOException if an I/O error occurs. + */ + public static boolean contentEquals(final FileChannel channel1, final FileChannel channel2, final int byteBufferSize) throws IOException { + // Short-circuit test + if (Objects.equals(channel1, channel2)) { + return true; + } + // Short-circuit test + final long size1 = size(channel1); + final long size2 = size(channel2); + if (size1 != size2) { + return false; + } + if (size1 == 0 && size2 == 0) { + return true; + } + // Dig in and do the work + final ByteBuffer byteBuffer1 = ByteBuffer.allocateDirect(byteBufferSize); + final ByteBuffer byteBuffer2 = ByteBuffer.allocateDirect(byteBufferSize); + while (true) { + final int read1 = channel1.read(byteBuffer1); + final int read2 = channel2.read(byteBuffer2); + if (read1 == IOUtils.EOF && read2 == IOUtils.EOF) { + return byteBuffer1.equals(byteBuffer2); + } + if (read1 != read2) { + return false; + } + if (!byteBuffer1.equals(byteBuffer2)) { + return false; + } + byteBuffer1.clear(); + byteBuffer2.clear(); + } + } + + private static long size(final FileChannel channel) throws IOException { + return channel != null ? channel.size() : 0; + } + + /** + * Don't instantiate. + */ + private FileChannels() { + // no-op + } +} diff --git a/src/main/java/org/apache/commons/io/channels/package-info.java b/src/main/java/org/apache/commons/io/channels/package-info.java new file mode 100644 index 00000000..51a7ca28 --- /dev/null +++ b/src/main/java/org/apache/commons/io/channels/package-info.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Provides classes to work with {@link java.nio.channels}. + * + * @since 2.15.0 + */ +package org.apache.commons.io.channels; diff --git a/src/main/java/org/apache/commons/io/comparator/CompositeFileComparator.java b/src/main/java/org/apache/commons/io/comparator/CompositeFileComparator.java index 0f57a833..d50f3252 100644 --- a/src/main/java/org/apache/commons/io/comparator/CompositeFileComparator.java +++ b/src/main/java/org/apache/commons/io/comparator/CompositeFileComparator.java @@ -19,6 +19,7 @@ package org.apache.commons.io.comparator; import java.io.File; import java.io.Serializable; import java.util.Comparator; +import java.util.function.IntFunction; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -48,6 +49,9 @@ public class CompositeFileComparator extends AbstractFileComparator implements S private static final Comparator<?>[] EMPTY_COMPARATOR_ARRAY = {}; private static final long serialVersionUID = -2224170307287243428L; + /** + * Delegates. + */ private final Comparator<File>[] delegates; /** @@ -65,7 +69,8 @@ public class CompositeFileComparator extends AbstractFileComparator implements S * @param delegates The delegate file comparators */ public CompositeFileComparator(final Iterable<Comparator<File>> delegates) { - this.delegates = delegates == null ? emptyArray() : StreamSupport.stream(delegates.spliterator(), false).toArray(Comparator[]::new); + this.delegates = delegates == null ? emptyArray() + : StreamSupport.stream(delegates.spliterator(), false).toArray((IntFunction<Comparator<File>[]>) Comparator[]::new); } /** 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..d85fdb67 100644 --- a/src/main/java/org/apache/commons/io/file/PathUtils.java +++ b/src/main/java/org/apache/commons/io/file/PathUtils.java @@ -21,7 +21,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.UncheckedIOException; +import java.io.RandomAccessFile; import java.math.BigInteger; import java.net.URI; import java.net.URISyntaxException; @@ -70,14 +70,14 @@ import java.util.stream.Stream; import org.apache.commons.io.Charsets; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; +import org.apache.commons.io.RandomAccessFileMode; +import org.apache.commons.io.RandomAccessFiles; import org.apache.commons.io.ThreadUtils; import org.apache.commons.io.file.Counters.PathCounters; import org.apache.commons.io.file.attribute.FileTimes; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.function.IOFunction; import org.apache.commons.io.function.IOSupplier; -import org.apache.commons.io.function.Uncheck; /** * NIO Path utilities. @@ -90,7 +90,7 @@ public final class PathUtils { * Private worker/holder that computes and tracks relative path names and their equality. We reuse the sorted relative * lists when comparing directories. */ - private static class RelativeSortedPaths { + private static final class RelativeSortedPaths { final boolean equals; // final List<Path> relativeDirList1; // might need later? @@ -365,7 +365,7 @@ public final class PathUtils { * Creates the parent directories for the given {@code path}. * <p> * If the parent directory already exists, then return it. - * <p> + * </p> * * @param path The path to a file (or directory). * @param attrs An optional list of file attributes to set atomically when creating the directories. @@ -381,7 +381,7 @@ public final class PathUtils { * Creates the parent directories for the given {@code path}. * <p> * If the parent directory already exists, then return it. - * <p> + * </p> * * @param path The path to a file (or directory). * @param linkOption A {@link LinkOption} or null. @@ -719,20 +719,20 @@ public final class PathUtils { /** * Compares the file contents of two Paths to determine if they are equal or not. * <p> - * File content is accessed through {@link Files#newInputStream(Path,OpenOption...)}. + * File content is accessed through {@link RandomAccessFileMode#create(Path)}. * </p> * * @param path1 the first stream. * @param path2 the second stream. * @param linkOptions options specifying how files are followed. - * @param openOptions options specifying how files are opened. + * @param openOptions ignored. * @return true if the content of the streams are equal or they both don't exist, false otherwise. * @throws NullPointerException if openOptions is null. * @throws IOException if an I/O error occurs. * @see org.apache.commons.io.FileUtils#contentEquals(java.io.File, java.io.File) */ public static boolean fileContentEquals(final Path path1, final Path path2, final LinkOption[] linkOptions, final OpenOption[] openOptions) - throws IOException { + throws IOException { if (path1 == null && path2 == null) { return true; } @@ -766,9 +766,9 @@ public final class PathUtils { // same file return true; } - try (InputStream inputStream1 = Files.newInputStream(nPath1, openOptions); - InputStream inputStream2 = Files.newInputStream(nPath2, openOptions)) { - return IOUtils.contentEquals(inputStream1, inputStream2); + try (RandomAccessFile raf1 = RandomAccessFileMode.READ_ONLY.create(path1.toRealPath(linkOptions)); + RandomAccessFile raf2 = RandomAccessFileMode.READ_ONLY.create(path2.toRealPath(linkOptions))) { + return RandomAccessFiles.contentEquals(raf1, raf2); } } @@ -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. @@ -1243,21 +1247,20 @@ public final class PathUtils { } /** - * Reads the BasicFileAttributes from the given path. Returns null instead of throwing - * {@link UnsupportedOperationException}. Throws {@link Uncheck} instead of {@link IOException}. + * Reads the BasicFileAttributes from the given path. Returns null if the attributes can't be read. * * @param <A> The {@link BasicFileAttributes} type * @param path The Path to test. * @param type the {@link Class} of the file attributes required to read. * @param options options indicating how to handle symbolic links. - * @return the file attributes. + * @return the file attributes or null if the attributes can't be read. * @see Files#readAttributes(Path, Class, LinkOption...) * @since 2.12.0 */ public static <A extends BasicFileAttributes> A readAttributes(final Path path, final Class<A> type, final LinkOption... options) { try { - return path == null ? null : Uncheck.apply(Files::readAttributes, path, type, options); - } catch (final UnsupportedOperationException e) { + return path == null ? null : Files.readAttributes(path, type, options); + } catch (final UnsupportedOperationException | IOException e) { // For example, on Windows. return null; } @@ -1270,16 +1273,14 @@ public final class PathUtils { * @return the path attributes. * @throws IOException if an I/O error occurs. * @since 2.9.0 - * @deprecated Will be removed in 3.0.0 in favor of {@link #readBasicFileAttributes(Path, LinkOption...)}. */ - @Deprecated public static BasicFileAttributes readBasicFileAttributes(final Path path) throws IOException { return Files.readAttributes(path, BasicFileAttributes.class); } /** - * Reads the BasicFileAttributes from the given path. Returns null instead of throwing - * {@link UnsupportedOperationException}. + * Reads the BasicFileAttributes from the given path. Returns null if the attributes + * can't be read. * * @param path the path to read. * @param options options indicating how to handle symbolic links. @@ -1291,12 +1292,11 @@ public final class PathUtils { } /** - * Reads the BasicFileAttributes from the given path. Returns null instead of throwing - * {@link UnsupportedOperationException}. + * Reads the BasicFileAttributes from the given path. Returns null if the attributes + * can't be read. * * @param path the path to read. * @return the path attributes. - * @throws UncheckedIOException if an I/O error occurs * @since 2.9.0 * @deprecated Use {@link #readBasicFileAttributes(Path, LinkOption...)}. */ @@ -1306,8 +1306,8 @@ public final class PathUtils { } /** - * Reads the DosFileAttributes from the given path. Returns null instead of throwing - * {@link UnsupportedOperationException}. + * Reads the DosFileAttributes from the given path. Returns null if the attributes + * can't be read. * * @param path the path to read. * @param options options indicating how to handle symbolic links. @@ -1323,8 +1323,8 @@ public final class PathUtils { } /** - * Reads the PosixFileAttributes or DosFileAttributes from the given path. Returns null instead of throwing - * {@link UnsupportedOperationException}. + * Reads the PosixFileAttributes or DosFileAttributes from the given path. Returns null if the attributes + * can't be read. * * @param path The Path to read. * @param options options indicating how to handle symbolic links. @@ -1751,6 +1751,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 @@ -1801,7 +1806,7 @@ public final class PathUtils { } /** - * Does allow to instantiate. + * Prevents instantiation. */ private PathUtils() { // do not instantiate. diff --git a/src/main/java/org/apache/commons/io/filefilter/DelegateFileFilter.java b/src/main/java/org/apache/commons/io/filefilter/DelegateFileFilter.java index 14c99566..ee2bb02b 100644 --- a/src/main/java/org/apache/commons/io/filefilter/DelegateFileFilter.java +++ b/src/main/java/org/apache/commons/io/filefilter/DelegateFileFilter.java @@ -39,7 +39,7 @@ public class DelegateFileFilter extends AbstractFileFilter implements Serializab /** The File filter */ private final FileFilter fileFilter; /** The Filename filter */ - private final FilenameFilter filenameFilter; + private final FilenameFilter fileNameFilter; /** * Constructs a delegate file filter around an existing FileFilter. @@ -49,17 +49,17 @@ public class DelegateFileFilter extends AbstractFileFilter implements Serializab public DelegateFileFilter(final FileFilter fileFilter) { Objects.requireNonNull(fileFilter, "filter"); this.fileFilter = fileFilter; - this.filenameFilter = null; + this.fileNameFilter = null; } /** * Constructs a delegate file filter around an existing FilenameFilter. * - * @param filenameFilter the filter to decorate + * @param fileNameFilter the filter to decorate */ - public DelegateFileFilter(final FilenameFilter filenameFilter) { - Objects.requireNonNull(filenameFilter, "filter"); - this.filenameFilter = filenameFilter; + public DelegateFileFilter(final FilenameFilter fileNameFilter) { + Objects.requireNonNull(fileNameFilter, "filter"); + this.fileNameFilter = fileNameFilter; this.fileFilter = null; } @@ -86,8 +86,8 @@ public class DelegateFileFilter extends AbstractFileFilter implements Serializab */ @Override public boolean accept(final File dir, final String name) { - if (filenameFilter != null) { - return filenameFilter.accept(dir, name); + if (fileNameFilter != null) { + return fileNameFilter.accept(dir, name); } return super.accept(dir, name); } @@ -99,7 +99,7 @@ public class DelegateFileFilter extends AbstractFileFilter implements Serializab */ @Override public String toString() { - final String delegate = fileFilter != null ? fileFilter.toString() : filenameFilter.toString(); + final String delegate = fileFilter != null ? fileFilter.toString() : fileNameFilter.toString(); return super.toString() + "(" + delegate + ")"; } diff --git a/src/main/java/org/apache/commons/io/filefilter/package-info.java b/src/main/java/org/apache/commons/io/filefilter/package-info.java index a374fb0d..3bf71238 100644 --- a/src/main/java/org/apache/commons/io/filefilter/package-info.java +++ b/src/main/java/org/apache/commons/io/filefilter/package-info.java @@ -40,7 +40,7 @@ * </tr> * <tr> * <td><a href="NameFileFilter.html">NameFileFilter</a></td> - * <td>Filter based on a filename</td> + * <td>Filter based on a file name</td> * </tr> * <tr> * <td><a href="WildcardFileFilter.html">WildcardFileFilter</a></td> diff --git a/src/main/java/org/apache/commons/io/input/ByteBufferCleaner.java b/src/main/java/org/apache/commons/io/input/ByteBufferCleaner.java index fc334e96..72b1b1e8 100644 --- a/src/main/java/org/apache/commons/io/input/ByteBufferCleaner.java +++ b/src/main/java/org/apache/commons/io/input/ByteBufferCleaner.java @@ -38,7 +38,7 @@ class ByteBufferCleaner { void clean(ByteBuffer buffer) throws ReflectiveOperationException; } - private static class Java8Cleaner implements Cleaner { + private static final class Java8Cleaner implements Cleaner { private final Method cleanerMethod; private final Method cleanMethod; @@ -57,7 +57,7 @@ class ByteBufferCleaner { } } - private static class Java9Cleaner implements Cleaner { + private static final class Java9Cleaner implements Cleaner { private final Object theUnsafe; private final Method invokeCleaner; diff --git a/src/main/java/org/apache/commons/io/input/MemoryMappedFileInputStream.java b/src/main/java/org/apache/commons/io/input/MemoryMappedFileInputStream.java index 89114be9..3d03f8ce 100644 --- a/src/main/java/org/apache/commons/io/input/MemoryMappedFileInputStream.java +++ b/src/main/java/org/apache/commons/io/input/MemoryMappedFileInputStream.java @@ -87,6 +87,9 @@ public final class MemoryMappedFileInputStream extends InputStream { */ public static class Builder extends AbstractStreamBuilder<MemoryMappedFileInputStream, Builder> { + /** + * Constructs a new Builder. + */ public Builder() { setBufferSizeDefault(DEFAULT_BUFFER_SIZE); setBufferSize(DEFAULT_BUFFER_SIZE); diff --git a/src/main/java/org/apache/commons/io/input/MessageDigestCalculatingInputStream.java b/src/main/java/org/apache/commons/io/input/MessageDigestCalculatingInputStream.java index 7aed4185..97d7ff59 100644 --- a/src/main/java/org/apache/commons/io/input/MessageDigestCalculatingInputStream.java +++ b/src/main/java/org/apache/commons/io/input/MessageDigestCalculatingInputStream.java @@ -21,12 +21,13 @@ import java.io.InputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Provider; +import java.util.Objects; import org.apache.commons.io.build.AbstractStreamBuilder; /** * This class is an example for using an {@link ObservableInputStream}. It creates its own {@link org.apache.commons.io.input.ObservableInputStream.Observer}, - * which calculates a checksum using a MessageDigest, for example an MD5 sum. + * which calculates a checksum using a {@link MessageDigest}, for example, a SHA-512 sum. * <p> * To build an instance, see {@link Builder}. * </p> @@ -35,12 +36,11 @@ import org.apache.commons.io.build.AbstractStreamBuilder; * Cryptography Architecture Standard Algorithm Name Documentation</a> for information about standard algorithm names. * </p> * <p> - * <em>Note</em>: Neither {@link ObservableInputStream}, nor {@link MessageDigest}, are thread safe. So is {@link MessageDigestCalculatingInputStream}. - * </p> - * <p> - * TODO Rename to MessageDigestInputStream in 3.0. + * <em>Note</em>: Neither {@link ObservableInputStream}, nor {@link MessageDigest}, are thread safe, so is {@link MessageDigestCalculatingInputStream}. * </p> + * @deprecated Use {@link MessageDigestInputStream}. */ +@Deprecated public class MessageDigestCalculatingInputStream extends ObservableInputStream { /** @@ -61,6 +61,9 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { private MessageDigest messageDigest; + /** + * Constructs a new Builder. + */ public Builder() { try { this.messageDigest = getDefaultMessageDigest(); @@ -92,6 +95,9 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { /** * Sets the message digest. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> * * @param messageDigest the message digest. */ @@ -101,6 +107,9 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { /** * Sets the name of the name of the message digest algorithm. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> * * @param algorithm the name of the algorithm. See the MessageDigest section in the * <a href= "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest"> Java Cryptography @@ -123,9 +132,10 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { * Constructs an MessageDigestMaintainingObserver for the given MessageDigest. * * @param messageDigest the message digest to use + * @throws NullPointerException if messageDigest is null. */ public MessageDigestMaintainingObserver(final MessageDigest messageDigest) { - this.messageDigest = messageDigest; + this.messageDigest = Objects.requireNonNull(messageDigest, "messageDigest"); } @Override @@ -187,9 +197,13 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { /** * Constructs a new instance, which calculates a signature on the given stream, using the given {@link MessageDigest}. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> * * @param inputStream the stream to calculate the message digest for * @param messageDigest the message digest to use + * @throws NullPointerException if messageDigest is null. * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}. */ @Deprecated @@ -200,6 +214,9 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { /** * Constructs a new instance, which calculates a signature on the given stream, using a {@link MessageDigest} with the given algorithm. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> * * @param inputStream the stream to calculate the message digest for * @param algorithm the name of the algorithm requested. See the MessageDigest section in the diff --git a/src/main/java/org/apache/commons/io/input/MessageDigestInputStream.java b/src/main/java/org/apache/commons/io/input/MessageDigestInputStream.java new file mode 100644 index 00000000..d822256b --- /dev/null +++ b/src/main/java/org/apache/commons/io/input/MessageDigestInputStream.java @@ -0,0 +1,193 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.io.input; + +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Objects; + +import org.apache.commons.io.build.AbstractStreamBuilder; + +/** + * This class is an example for using an {@link ObservableInputStream}. It creates its own {@link org.apache.commons.io.input.ObservableInputStream.Observer}, + * which calculates a checksum using a {@link MessageDigest}, for example, a SHA-512 sum. + * <p> + * To build an instance, see {@link Builder}. + * </p> + * <p> + * See the MessageDigest section in the <a href= "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest"> Java + * Cryptography Architecture Standard Algorithm Name Documentation</a> for information about standard algorithm names. + * </p> + * <p> + * You must specify a message digest algorithm name or instance. + * </p> + * <p> + * <em>Note</em>: Neither {@link ObservableInputStream}, nor {@link MessageDigest}, are thread safe, so is {@link MessageDigestInputStream}. + * </p> + * + * @since 2.15.0 + */ +public final class MessageDigestInputStream extends ObservableInputStream { + + /** + * Builds new {@link MessageDigestInputStream} instances. + * <p> + * For example: + * </p> + * <pre>{@code + * MessageDigestInputStream s = MessageDigestInputStream.builder() + * .setPath(path) + * .setMessageDigest("SHA-512") + * .get();} + * </pre> + * <p> + * You must specify a message digest algorithm name or instance. + * </p> + */ + public static class Builder extends AbstractStreamBuilder<MessageDigestInputStream, Builder> { + + private MessageDigest messageDigest; + + /** + * Constructs a new Builder. + */ + public Builder() { + // empty + } + + /** + * Constructs a new instance. + * <p> + * This builder use the aspects InputStream, OpenOption[], and MessageDigest. + * </p> + * <p> + * You must provide an origin that can be converted to an InputStream by this builder, otherwise, this call will throw an + * {@link UnsupportedOperationException}. + * </p> + * + * @return a new instance. + * @throws UnsupportedOperationException if the origin cannot provide an InputStream. + * @see #getInputStream() + */ + @SuppressWarnings("resource") + @Override + public MessageDigestInputStream get() throws IOException { + return new MessageDigestInputStream(getInputStream(), messageDigest); + } + + /** + * Sets the message digest. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> + * + * @param messageDigest the message digest. + * @return this + */ + public Builder setMessageDigest(final MessageDigest messageDigest) { + this.messageDigest = messageDigest; + return this; + } + + /** + * Sets the name of the name of the message digest algorithm. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> + * + * @param algorithm the name of the algorithm. See the MessageDigest section in the + * <a href= "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest"> Java Cryptography + * Architecture Standard Algorithm Name Documentation</a> for information about standard algorithm names. + * @return this + * @throws NoSuchAlgorithmException if no Provider supports a MessageDigestSpi implementation for the specified algorithm. + */ + public Builder setMessageDigest(final String algorithm) throws NoSuchAlgorithmException { + this.messageDigest = MessageDigest.getInstance(algorithm); + return this; + } + + } + + /** + * Maintains the message digest. + */ + public static class MessageDigestMaintainingObserver extends Observer { + + private final MessageDigest messageDigest; + + /** + * Constructs an MessageDigestMaintainingObserver for the given MessageDigest. + * + * @param messageDigest the message digest to use + * @throws NullPointerException if messageDigest is null. + */ + public MessageDigestMaintainingObserver(final MessageDigest messageDigest) { + this.messageDigest = Objects.requireNonNull(messageDigest, "messageDigest"); + } + + @Override + public void data(final byte[] input, final int offset, final int length) throws IOException { + messageDigest.update(input, offset, length); + } + + @Override + public void data(final int input) throws IOException { + messageDigest.update((byte) input); + } + } + + /** + * Constructs a new {@link Builder}. + * + * @return a new {@link Builder}. + */ + public static Builder builder() { + return new Builder(); + } + + private final MessageDigest messageDigest; + + /** + * Constructs a new instance, which calculates a signature on the given stream, using the given {@link MessageDigest}. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> + * + * @param inputStream the stream to calculate the message digest for + * @param messageDigest the message digest to use + * @throws NullPointerException if messageDigest is null. + */ + private MessageDigestInputStream(final InputStream inputStream, final MessageDigest messageDigest) { + super(inputStream, new MessageDigestMaintainingObserver(messageDigest)); + this.messageDigest = messageDigest; + } + + /** + * Gets the {@link MessageDigest}, which is being used for generating the checksum. + * <p> + * <em>Note</em>: The checksum will only reflect the data, which has been read so far. This is probably not, what you expect. Make sure, that the complete + * data has been read, if that is what you want. The easiest way to do so is by invoking {@link #consume()}. + * </p> + * + * @return the message digest used + */ + public MessageDigest getMessageDigest() { + return messageDigest; + } +} diff --git a/src/main/java/org/apache/commons/io/input/ObservableInputStream.java b/src/main/java/org/apache/commons/io/input/ObservableInputStream.java index ee080f06..a97702fb 100644 --- a/src/main/java/org/apache/commons/io/input/ObservableInputStream.java +++ b/src/main/java/org/apache/commons/io/input/ObservableInputStream.java @@ -39,7 +39,7 @@ import org.apache.commons.io.function.IOConsumer; * be used. * </p> * - * @see MessageDigestCalculatingInputStream + * @see MessageDigestInputStream */ public class ObservableInputStream extends ProxyInputStream { diff --git a/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java b/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java index 04c9cf91..7ef620fe 100644 --- a/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java +++ b/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java @@ -66,6 +66,9 @@ public class ReversedLinesFileReader implements Closeable { */ public static class Builder extends AbstractStreamBuilder<ReversedLinesFileReader, Builder> { + /** + * Constructs a new Builder. + */ public Builder() { setBufferSizeDefault(DEFAULT_BLOCK_SIZE); setBufferSize(DEFAULT_BLOCK_SIZE); diff --git a/src/main/java/org/apache/commons/io/input/SwappedDataInputStream.java b/src/main/java/org/apache/commons/io/input/SwappedDataInputStream.java index 31600f58..9239b520 100644 --- a/src/main/java/org/apache/commons/io/input/SwappedDataInputStream.java +++ b/src/main/java/org/apache/commons/io/input/SwappedDataInputStream.java @@ -29,7 +29,7 @@ import org.apache.commons.io.EndianUtils; * DataInput for systems relying on little endian data formats. When read, values will be changed from little endian to * big endian formats for internal usage. * <p> - * <b>Origin of code: </b>Avalon Excalibur (IO) + * Provenance: Avalon Excalibur (IO) * </p> */ public class SwappedDataInputStream extends ProxyInputStream implements DataInput { diff --git a/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStream.java b/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStream.java index ffd456df..b33a1187 100644 --- a/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStream.java +++ b/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStream.java @@ -105,7 +105,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte protected volatile byte[] buffer; /** - * The total number of bytes inside the byte array {@code buf}. + * The total number of bytes inside the byte array {@code buffer}. */ protected int count; @@ -120,7 +120,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte protected int markPos = IOUtils.EOF; /** - * The current position within the byte array {@code buf}. + * The current position within the byte array {@code buffer}. */ protected int pos; @@ -190,8 +190,8 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte } final byte[] newbuf = new byte[newLength]; System.arraycopy(localBuf, 0, newbuf, 0, localBuf.length); - // Reassign buf, which will invalidate any local references - // FIXME: what if buf was null? + // Reassign buffer, which will invalidate any local references + // FIXME: what if buffer was null? localBuf = buffer = newbuf; } else if (markPos > 0) { System.arraycopy(localBuf, markPos, localBuf, 0, localBuf.length - markPos); @@ -276,7 +276,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte * set and the requested number of bytes is larger than the receiver's buffer size, this implementation bypasses the buffer and simply places the results * directly into {@code buffer}. * - * @param buffer the byte array in which to store the bytes read. + * @param dest the byte array in which to store the bytes read. * @param offset the initial position in {@code buffer} to store the bytes read from this stream. * @param length the maximum number of bytes to store in {@code buffer}. * @return the number of bytes actually read or -1 if end of stream. @@ -284,7 +284,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte * @throws IOException if the stream is already closed or another IOException occurs. */ @Override - public int read(final byte[] buffer, int offset, final int length) throws IOException { + public int read(final byte[] dest, int offset, final int length) throws IOException { // Use local ref since buf may be invalidated by an unsynchronized // close() byte[] localBuf = buffer; @@ -292,7 +292,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte throw new IOException("Stream is closed"); } // avoid int overflow - if (offset > buffer.length - length || offset < 0 || length < 0) { + if (offset > dest.length - length || offset < 0 || length < 0) { throw new IndexOutOfBoundsException(); } if (length == 0) { @@ -307,7 +307,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte if (pos < count) { /* There are bytes available in the buffer. */ final int copylength = count - pos >= length ? length : count - pos; - System.arraycopy(localBuf, pos, buffer, offset, copylength); + System.arraycopy(localBuf, pos, dest, offset, copylength); pos += copylength; if (copylength == length || localIn.available() == 0) { return copylength; @@ -324,7 +324,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte * If we're not marked and the required size is greater than the buffer, simply read the bytes directly bypassing the buffer. */ if (markPos == IOUtils.EOF && required >= localBuf.length) { - read = localIn.read(buffer, offset, required); + read = localIn.read(dest, offset, required); if (read == IOUtils.EOF) { return required == length ? IOUtils.EOF : length - required; } @@ -341,7 +341,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte } read = count - pos >= required ? required : count - pos; - System.arraycopy(localBuf, pos, buffer, offset, read); + System.arraycopy(localBuf, pos, dest, offset, read); pos += read; } required -= read; @@ -397,10 +397,12 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte } if (count - pos >= amount) { - pos += amount; + // (int count - int pos) here is always an int so amount is also in the int range if the above test is true. + // We can safely cast to int and avoid static analysis warnings. + pos += (int) amount; return amount; } - long read = count - pos; + int read = count - pos; pos = count; if (markPos != IOUtils.EOF && amount <= markLimit) { @@ -408,7 +410,9 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte return read; } if (count - pos >= amount - read) { - pos += amount - read; + // (int count - int pos) here is always an int so (amount - read) is also in the int range if the above test is true. + // We can safely cast to int and avoid static analysis warnings. + pos += (int) amount - read; return amount; } // Couldn't get all the bytes, skip what we read diff --git a/src/main/java/org/apache/commons/io/input/UnsynchronizedByteArrayInputStream.java b/src/main/java/org/apache/commons/io/input/UnsynchronizedByteArrayInputStream.java index a4fc696c..f10c1120 100644 --- a/src/main/java/org/apache/commons/io/input/UnsynchronizedByteArrayInputStream.java +++ b/src/main/java/org/apache/commons/io/input/UnsynchronizedByteArrayInputStream.java @@ -106,6 +106,12 @@ public class UnsynchronizedByteArrayInputStream extends InputStream { return super.setByteArray(origin); } + /** + * Sets the length. + * + * @param length Must be greater or equal to 0. + * @return this. + */ public Builder setLength(final int length) { if (length < 0) { throw new IllegalArgumentException("length cannot be negative"); @@ -114,6 +120,12 @@ public class UnsynchronizedByteArrayInputStream extends InputStream { return this; } + /** + * Sets the offset. + * + * @param offset Must be greater or equal to 0. + * @return this. + */ public Builder setOffset(final int offset) { if (offset < 0) { throw new IllegalArgumentException("offset cannot be negative"); diff --git a/src/main/java/org/apache/commons/io/input/XmlStreamReader.java b/src/main/java/org/apache/commons/io/input/XmlStreamReader.java index a38ef807..290e5360 100644 --- a/src/main/java/org/apache/commons/io/input/XmlStreamReader.java +++ b/src/main/java/org/apache/commons/io/input/XmlStreamReader.java @@ -157,11 +157,23 @@ public class XmlStreamReader extends Reader { return super.setCharset(Charsets.toCharset(charset, getCharsetDefault())); } + /** + * Sets the HTTP content type. + * + * @param httpContentType the HTTP content type. + * @return this. + */ public Builder setHttpContentType(final String httpContentType) { this.httpContentType = httpContentType; return this; } + /** + * Sets the lenient toggle. + * + * @param lenient the lenient toggle. + * @return this. + */ public Builder setLenient(final boolean lenient) { this.lenient = lenient; return this; @@ -209,8 +221,14 @@ public class XmlStreamReader extends Reader { // @formatter:off "^<\\?xml\\s+" + "version\\s*=\\s*(?:(?:\"1\\.[0-9]+\")|(?:'1.[0-9]+'))\\s+" - + "encoding\\s*=\\s*((?:\"[A-Za-z]([A-Za-z0-9\\._]|-)*\")|(?:'[A-Za-z]([A-Za-z0-9\\\\._]|-)*'))", + + "encoding\\s*=\\s*" + + "((?:\"[A-Za-z0-9][A-Za-z0-9._+:-]*\")" // double-quoted + + "|(?:'[A-Za-z0-9][A-Za-z0-9._+:-]*'))", // single-quoted Pattern.MULTILINE); + // N.B. the documented pattern is + // EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* + // However this does not match all the aliases that are supported by Java. + // e.g. '437', 'ISO_8859-1:1987' and 'ebcdic-de-273+euro' // @formatter:on private static final String RAW_EX_1 = "Illegal encoding, BOM [{0}] XML guess [{1}] XML prolog [{2}] encoding mismatch"; diff --git a/src/main/java/org/apache/commons/io/output/DeferredFileOutputStream.java b/src/main/java/org/apache/commons/io/output/DeferredFileOutputStream.java index d4dc19e9..3382bdcd 100644 --- a/src/main/java/org/apache/commons/io/output/DeferredFileOutputStream.java +++ b/src/main/java/org/apache/commons/io/output/DeferredFileOutputStream.java @@ -70,6 +70,9 @@ public class DeferredFileOutputStream extends ThresholdingOutputStream { private String suffix; private Path directory; + /** + * Constructs a new builder. + */ public Builder() { setBufferSizeDefault(AbstractByteArrayOutputStream.DEFAULT_SIZE); setBufferSize(AbstractByteArrayOutputStream.DEFAULT_SIZE); @@ -265,28 +268,6 @@ public class DeferredFileOutputStream extends ThresholdingOutputStream { } /** - * Constructs an instance of this class which will trigger an event at the specified threshold, and save data either to a file beyond that point. - * - * @param threshold The number of bytes at which to trigger an event. - * @param outputFile The file to which data is saved beyond the threshold. - * @param prefix Prefix to use for the temporary file. - * @param suffix Suffix to use for the temporary file. - * @param directory Temporary file directory. - * @param initialBufferSize The initial size of the in memory buffer. - * @throws IllegalArgumentException if initialBufferSize < 0. - */ - private DeferredFileOutputStream(final int threshold, final Path outputFile, final String prefix, final String suffix, final Path directory, - final int initialBufferSize) { - super(threshold); - this.outputPath = toPath(outputFile, null); - this.prefix = prefix; - this.suffix = suffix; - this.directory = toPath(directory, PathUtils::getTempDirectory); - this.memoryOutputStream = new ByteArrayOutputStream(checkBufferSize(initialBufferSize)); - this.currentOutputStream = memoryOutputStream; - } - - /** * Constructs an instance of this class which will trigger an event at the specified threshold, and save data to a file beyond that point. * * @param threshold The number of bytes at which to trigger an event. @@ -317,6 +298,28 @@ public class DeferredFileOutputStream extends ThresholdingOutputStream { } /** + * Constructs an instance of this class which will trigger an event at the specified threshold, and save data either to a file beyond that point. + * + * @param threshold The number of bytes at which to trigger an event. + * @param outputFile The file to which data is saved beyond the threshold. + * @param prefix Prefix to use for the temporary file. + * @param suffix Suffix to use for the temporary file. + * @param directory Temporary file directory. + * @param initialBufferSize The initial size of the in memory buffer. + * @throws IllegalArgumentException if initialBufferSize < 0. + */ + private DeferredFileOutputStream(final int threshold, final Path outputFile, final String prefix, final String suffix, final Path directory, + final int initialBufferSize) { + super(threshold); + this.outputPath = toPath(outputFile, null); + this.prefix = prefix; + this.suffix = suffix; + this.directory = toPath(directory, PathUtils::getTempDirectory); + this.memoryOutputStream = new ByteArrayOutputStream(checkBufferSize(initialBufferSize)); + this.currentOutputStream = memoryOutputStream; + } + + /** * Constructs an instance of this class which will trigger an event at the specified threshold, and save data to a temporary file beyond that point. The * initial buffer size will default to 32 bytes which is ByteArrayOutputStream's default buffer size. * diff --git a/src/main/java/org/apache/commons/io/output/LockableFileWriter.java b/src/main/java/org/apache/commons/io/output/LockableFileWriter.java index 064de220..b33abc81 100644 --- a/src/main/java/org/apache/commons/io/output/LockableFileWriter.java +++ b/src/main/java/org/apache/commons/io/output/LockableFileWriter.java @@ -70,6 +70,9 @@ public class LockableFileWriter extends Writer { private boolean append; private AbstractOrigin<?, ?> lockDirectory = AbstractOriginSupplier.newFileOrigin(FileUtils.getTempDirectoryPath()); + /** + * Constructs a new Builder. + */ public Builder() { setBufferSizeDefault(AbstractByteArrayOutputStream.DEFAULT_SIZE); setBufferSize(AbstractByteArrayOutputStream.DEFAULT_SIZE); diff --git a/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java b/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java index 1d8a3a03..8102eb58 100644 --- a/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java +++ b/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java @@ -149,11 +149,10 @@ public class ThresholdingOutputStream extends OutputStream { * * @return The underlying output stream. * @throws IOException if an error occurs. - * @deprecated Use {@link #getOutputStream()}. + * @since 2.14.0 */ - @Deprecated - protected OutputStream getStream() throws IOException { - return getOutputStream(); + protected OutputStream getOutputStream() throws IOException { + return outputStreamGetter.apply(this); } /** @@ -162,10 +161,11 @@ public class ThresholdingOutputStream extends OutputStream { * * @return The underlying output stream. * @throws IOException if an error occurs. - * @since 2.14.0 + * @deprecated Use {@link #getOutputStream()}. */ - protected OutputStream getOutputStream() throws IOException { - return outputStreamGetter.apply(this); + @Deprecated + protected OutputStream getStream() throws IOException { + return getOutputStream(); } /** diff --git a/src/main/java/org/apache/commons/io/output/WriterOutputStream.java b/src/main/java/org/apache/commons/io/output/WriterOutputStream.java index dc4cd6fd..bc2c5c21 100644 --- a/src/main/java/org/apache/commons/io/output/WriterOutputStream.java +++ b/src/main/java/org/apache/commons/io/output/WriterOutputStream.java @@ -99,6 +99,9 @@ public class WriterOutputStream extends OutputStream { private CharsetDecoder charsetDecoder; private boolean writeImmediately; + /** + * Constructs a new Builder. + */ public Builder() { this.charsetDecoder = getCharset().newDecoder(); } diff --git a/src/main/java/org/apache/commons/io/output/XmlStreamWriter.java b/src/main/java/org/apache/commons/io/output/XmlStreamWriter.java index b40a2aca..6f732a72 100644 --- a/src/main/java/org/apache/commons/io/output/XmlStreamWriter.java +++ b/src/main/java/org/apache/commons/io/output/XmlStreamWriter.java @@ -62,6 +62,9 @@ public class XmlStreamWriter extends Writer { */ public static class Builder extends AbstractStreamBuilder<XmlStreamWriter, Builder> { + /** + * Constructs a new Builder. + */ public Builder() { setCharsetDefault(StandardCharsets.UTF_8); setCharset(StandardCharsets.UTF_8); diff --git a/src/main/java/org/apache/commons/io/package-info.java b/src/main/java/org/apache/commons/io/package-info.java index 29464fe9..6633c106 100644 --- a/src/main/java/org/apache/commons/io/package-info.java +++ b/src/main/java/org/apache/commons/io/package-info.java @@ -24,7 +24,7 @@ * <b>FileUtils</b> provides operations based around the JDK File class. These include reading, writing, copying, comparing and deleting. * </p> * <p> - * <b>FilenameUtils</b> provides utilities based on filenames. This utility class manipulates filenames without using File objects. It aims to simplify the + * <b>FilenameUtils</b> provides utilities based on filenames. This utility class manipulates file names without using File objects. It aims to simplify the * transition between Windows and Unix. Before using this class however, you should consider whether you should be using File objects. * </p> * <p> diff --git a/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java b/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java index bde163c7..6e60f32e 100644 --- a/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java +++ b/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java @@ -110,6 +110,32 @@ public class ValidatingObjectInputStream extends ObjectInputStream { } /** + * Checks that the class name conforms to requirements. + * + * @param name The class name + * @throws InvalidClassException when a non-accepted class is encountered + */ + private void checkClassName(final String name) throws InvalidClassException { + // Reject has precedence over accept + for (final ClassNameMatcher m : rejectMatchers) { + if (m.matches(name)) { + invalidClassNameFound(name); + } + } + + boolean ok = false; + for (final ClassNameMatcher m : acceptMatchers) { + if (m.matches(name)) { + ok = true; + break; + } + } + if (!ok) { + invalidClassNameFound(name); + } + } + + /** * Called to throw {@link InvalidClassException} if an invalid * class name is found during deserialization. Can be overridden, for example * to log those class names. @@ -172,31 +198,7 @@ public class ValidatingObjectInputStream extends ObjectInputStream { @Override protected Class<?> resolveClass(final ObjectStreamClass osc) throws IOException, ClassNotFoundException { - validateClassName(osc.getName()); + checkClassName(osc.getName()); return super.resolveClass(osc); } - - /** Check that the classname conforms to requirements. - * @param name The class name - * @throws InvalidClassException when a non-accepted class is encountered - */ - private void validateClassName(final String name) throws InvalidClassException { - // Reject has precedence over accept - for (final ClassNameMatcher m : rejectMatchers) { - if (m.matches(name)) { - invalidClassNameFound(name); - } - } - - boolean ok = false; - for (final ClassNameMatcher m : acceptMatchers) { - if (m.matches(name)) { - ok = true; - break; - } - } - if (!ok) { - invalidClassNameFound(name); - } - } }
\ No newline at end of file |