2525import java .io .InputStream ;
2626import java .io .OutputStream ;
2727import java .net .URL ;
28+ import java .net .URLConnection ;
2829import java .nio .channels .FileChannel ;
2930import java .util .ArrayList ;
3031import java .util .Collection ;
@@ -1007,6 +1008,10 @@ private static void doCopyDirectory(File srcDir, File destDir, FileFilter filter
10071008 * <code>destination</code>. The directories up to <code>destination</code>
10081009 * will be created if they don't already exist. <code>destination</code>
10091010 * will be overwritten if it already exists.
1011+ * <p>
1012+ * Warning: this method does not set a connection or read timeout and thus
1013+ * might block forever. Use {@link #copyURLToFile(URL, File, int, int)}
1014+ * with reasonable timeouts to prevent this.
10101015 *
10111016 * @param source the <code>URL</code> to copy bytes from, must not be <code>null</code>
10121017 * @param destination the non-directory <code>File</code> to write bytes to
@@ -1019,15 +1024,64 @@ private static void doCopyDirectory(File srcDir, File destDir, FileFilter filter
10191024 */
10201025 public static void copyURLToFile (URL source , File destination ) throws IOException {
10211026 InputStream input = source .openStream ();
1027+ copyInputStreamToFile (input , destination );
1028+ }
1029+
1030+ /**
1031+ * Copies bytes from the URL <code>source</code> to a file
1032+ * <code>destination</code>. The directories up to <code>destination</code>
1033+ * will be created if they don't already exist. <code>destination</code>
1034+ * will be overwritten if it already exists.
1035+ *
1036+ * @param source the <code>URL</code> to copy bytes from, must not be <code>null</code>
1037+ * @param destination the non-directory <code>File</code> to write bytes to
1038+ * (possibly overwriting), must not be <code>null</code>
1039+ * @param connectionTimeout the number of milliseconds until this method
1040+ * will timeout if no connection could be established to the <code>source</code>
1041+ * @param readTimeout the number of milliseconds until this method will
1042+ * timeout if no data could be read from the <code>source</code>
1043+ * @throws IOException if <code>source</code> URL cannot be opened
1044+ * @throws IOException if <code>destination</code> is a directory
1045+ * @throws IOException if <code>destination</code> cannot be written
1046+ * @throws IOException if <code>destination</code> needs creating but can't be
1047+ * @throws IOException if an IO error occurs during copying
1048+ * @since Commons IO 2.0
1049+ */
1050+ public static void copyURLToFile (URL source , File destination ,
1051+ int connectionTimeout , int readTimeout ) throws IOException {
1052+ URLConnection connection = source .openConnection ();
1053+ connection .setConnectTimeout (connectionTimeout );
1054+ connection .setReadTimeout (readTimeout );
1055+ InputStream input = connection .getInputStream ();
1056+ copyInputStreamToFile (input , destination );
1057+ }
1058+
1059+ /**
1060+ * Copies bytes from an {@link InputStream} <code>source</code> to a file
1061+ * <code>destination</code>. The directories up to <code>destination</code>
1062+ * will be created if they don't already exist. <code>destination</code>
1063+ * will be overwritten if it already exists.
1064+ *
1065+ * @param source the <code>InputStream</code> to copy bytes from, must not be <code>null</code>
1066+ * @param destination the non-directory <code>File</code> to write bytes to
1067+ * (possibly overwriting), must not be <code>null</code>
1068+ * @throws IOException if <code>source</code> URL cannot be opened
1069+ * @throws IOException if <code>destination</code> is a directory
1070+ * @throws IOException if <code>destination</code> cannot be written
1071+ * @throws IOException if <code>destination</code> needs creating but can't be
1072+ * @throws IOException if an IO error occurs during copying
1073+ * @since Commons IO 2.0
1074+ */
1075+ public static void copyInputStreamToFile (InputStream source , File destination ) throws IOException {
10221076 try {
10231077 FileOutputStream output = openOutputStream (destination );
10241078 try {
1025- IOUtils .copy (input , output );
1079+ IOUtils .copy (source , output );
10261080 } finally {
10271081 IOUtils .closeQuietly (output );
10281082 }
10291083 } finally {
1030- IOUtils .closeQuietly (input );
1084+ IOUtils .closeQuietly (source );
10311085 }
10321086 }
10331087
0 commit comments