Para resumir (y de alguna manera pulir y actualizar) respuestas anteriores. Los tres métodos siguientes son prácticamente equivalentes. (Agregué tiempos de espera explícitos porque creo que son imprescindibles, nadie quiere que una descarga se congele para siempre cuando se pierde la conexión).
public static void saveUrl1(final Path file, final URL url,
int secsConnectTimeout, int secsReadTimeout))
throws MalformedURLException, IOException {
// Files.createDirectories(file.getParent()); // optional, make sure parent dir exists
try (BufferedInputStream in = new BufferedInputStream(
streamFromUrl(url, secsConnectTimeout,secsReadTimeout) );
OutputStream fout = Files.newOutputStream(file)) {
final byte data[] = new byte[8192];
int count;
while((count = in.read(data)) > 0)
fout.write(data, 0, count);
}
}
public static void saveUrl2(final Path file, final URL url,
int secsConnectTimeout, int secsReadTimeout))
throws MalformedURLException, IOException {
// Files.createDirectories(file.getParent()); // optional, make sure parent dir exists
try (ReadableByteChannel rbc = Channels.newChannel(
streamFromUrl(url, secsConnectTimeout,secsReadTimeout)
);
FileChannel channel = FileChannel.open(file,
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.WRITE)
) {
channel.transferFrom(rbc, 0, Long.MAX_VALUE);
}
}
public static void saveUrl3(final Path file, final URL url,
int secsConnectTimeout, int secsReadTimeout))
throws MalformedURLException, IOException {
// Files.createDirectories(file.getParent()); // optional, make sure parent dir exists
try (InputStream in = streamFromUrl(url, secsConnectTimeout,secsReadTimeout) ) {
Files.copy(in, file, StandardCopyOption.REPLACE_EXISTING);
}
}
public static InputStream streamFromUrl(URL url,int secsConnectTimeout,int secsReadTimeout) throws IOException {
URLConnection conn = url.openConnection();
if(secsConnectTimeout>0) conn.setConnectTimeout(secsConnectTimeout*1000);
if(secsReadTimeout>0) conn.setReadTimeout(secsReadTimeout*1000);
return conn.getInputStream();
}
No encuentro diferencias significativas, todo me parece correcto. Son seguros y eficientes. (Las diferencias de velocidad parecen poco relevantes: escribo 180 Mb desde el servidor local en un disco SSD en tiempos que fluctúan alrededor de 1.2 a 1.5 segs). No requieren bibliotecas externas. Todos funcionan con tamaños arbitrarios y (según mi experiencia) redirecciones HTTP.
Además, todos se lanzan FileNotFoundException
si no se encuentra el recurso (error 404, por lo general) y java.net.UnknownHostException
si falla la resolución de DNS; otras IOException corresponden a errores durante la transmisión.
(Marcado como wiki de la comunidad, siéntase libre de agregar información o correcciones)