Add IOUtils.copy(URL, File) and copy(URL, OutputStream).
MODIFY
src/changes/changes.xml
src/changes/changes.xml
@@ -175,6 +175,12 @@ The <action> type attribute can be add,update,fix,remove.
<action dev="ggregory" type="add" due-to="Gary Gregory">
Make public and reuse IOUtils.EMPTY_BYTE_ARRAY.
</action>
+ <action dev="ggregory" type="add" due-to="Gary Gregory">
+ Add IOUtils.copy(URL, File).
+ </action>
+ <action dev="ggregory" type="add" due-to="Gary Gregory">
+ Add copy(URL, OutputStream).
+ </action>
<!-- UPDATES -->
<action dev="ggregory" type="update" due-to="Dependabot">
Update junit-jupiter from 5.6.2 to 5.7.0 #153.

MODIFY
src/main/java/org/apache/commons/io/IOUtils.java
src/main/java/org/apache/commons/io/IOUtils.java
import java.io.Closeable;
import java.io.EOFException;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -1190,6 +1191,52 @@ public static int copy(final Reader reader, final Writer writer) throws IOExcept
return (int) count;
}
+ /**
+ * Copies bytes from a {@code URL} to an {@code OutputStream}.
+ * <p>
+ * This method buffers the input internally, so there is no need to use a {@code BufferedInputStream}.
+ * </p>
+ * <p>
+ * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}.
+ * </p>
+ *
+ * @param url the {@code URL} to read.
+ * @param file the {@code OutputStream} to write.
+ * @return the number of bytes copied.
+ * @throws NullPointerException if the URL is {@code null}.
+ * @throws NullPointerException if the OutputStream is {@code null}.
+ * @throws IOException if an I/O error occurs.
+ * @since 2.9.0
+ */
+ public static long copy(final URL url, final File file) throws IOException {
+ try (FileOutputStream outputStream = new FileOutputStream(Objects.requireNonNull(file, "file"))) {
+ return copy(url, outputStream);
+ }
+ }
+
+ /**
+ * Copies bytes from a {@code URL} to an {@code OutputStream}.
+ * <p>
+ * This method buffers the input internally, so there is no need to use a {@code BufferedInputStream}.
+ * </p>
+ * <p>
+ * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}.
+ * </p>
+ *
+ * @param url the {@code URL} to read.
+ * @param outputStream the {@code OutputStream} to write.
+ * @return the number of bytes copied.
+ * @throws NullPointerException if the URL is {@code null}.
+ * @throws NullPointerException if the OutputStream is {@code null}.
+ * @throws IOException if an I/O error occurs.
+ * @since 2.9.0
+ */
+ public static long copy(final URL url, final OutputStream outputStream) throws IOException {
+ try (InputStream inputStream = Objects.requireNonNull(url, "url").openStream()) {
+ return copyLarge(inputStream, outputStream);
+ }
+ }
+
/**
* Copies bytes from a large (over 2GB) {@code InputStream} to an
* {@code OutputStream}.

MODIFY
src/test/java/org/apache/commons/io/IOUtilsCopyTestCase.java
src/test/java/org/apache/commons/io/IOUtilsCopyTestCase.java
*/
package org.apache.commons.io;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
+import java.net.URL;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Arrays;
import org.apache.commons.io.input.NullInputStream;
@@ -431,4 +437,32 @@ public void testCopy_readerToWriter_nullOut() {
assertThrows(NullPointerException.class, () -> IOUtils.copy(reader, (Writer) null));
}
+ @Test
+ public void testCopy_URLToFile() throws Exception {
+ final String name = "/org/apache/commons/io/abitmorethan16k.txt";
+ URL in = getClass().getResource(name);
+ assertNotNull(in, name);
+
+ Path path = Files.createTempFile("testCopy_URLToFile", ".txt");
+ try {
+ IOUtils.copy(in, path.toFile());
+
+ assertArrayEquals(Files.readAllBytes(Paths.get("src/test/resources" + name)), Files.readAllBytes(path));
+ } finally {
+ Files.delete(path);
+ }
+ }
+
+ @Test
+ public void testCopy_URLToOutputStream() throws Exception {
+ final String name = "/org/apache/commons/io/abitmorethan16k.txt";
+ URL in = getClass().getResource(name);
+ assertNotNull(in, name);
+
+ final ByteArrayOutputStream baout = new ByteArrayOutputStream();
+ IOUtils.copy(in, baout);
+
+ assertArrayEquals(Files.readAllBytes(Paths.get("src/test/resources" + name)), baout.toByteArray());
+ }
+
}

Add IOUtils.copy(URL, File) and copy(URL, OutputStream).