Para resumir (e de alguma forma polir e atualizar) as respostas anteriores. Os três métodos a seguir são praticamente equivalentes. (Adicionei tempos limite explícitos porque acho que eles são obrigatórios, ninguém quer que um download seja congelado para sempre quando a conexão for perdida.)
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();
}
Não encontro diferenças significativas, tudo parece correto para mim. Eles são seguros e eficientes. (As diferenças de velocidade parecem pouco relevantes - eu escrevo 180 Mb do servidor local em um disco SSD em momentos que variam em torno de 1,2 a 1,5 segs). Eles não exigem bibliotecas externas. Todos trabalham com tamanhos arbitrários e (para minha experiência) redirecionamentos HTTP.
Além disso, todos são lançados FileNotFoundException
se o recurso não for encontrado (erro 404, normalmente) e java.net.UnknownHostException
se a resolução do DNS falhar; outra IOException corresponde a erros durante a transmissão.
(Marcado como wiki da comunidade, adicione informações ou correções)