Estoy intentando descargar un archivo desde una URL. Hay muchos recursos y no sé cuál me necesidad de cerrar o no simplemente tener que cerrar todos ellos?
public void downloadUpdate(final String url) {
try {
/* Which of these resources do I need to close? */
final InputStream inputStream = new URL(url).openStream();
final ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream);
final FileOutputStream fileOutputStream = new FileOutputStream(Bukkit.getServer().getUpdateFolderFile());
final FileChannel fileChannel = fileOutputStream.getChannel();
/* Downloading the update... */
fileChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
} catch (final IOException exception) {
exception.printStackTrace();
}
}
En su caso, probablemente los únicos recursos que necesitan ser cerrado son los InputStream
e FileOutputStream
. Sin embargo, ¿por qué no simplemente cerrar todo mediante el uso de try-con-recursos? No se pierde nada de llamar Closeable#close()
por si acaso 1 . De hecho, es probable que debe cerrar todas Closeable
en su control (es decir, que abrió) cuando haya terminado con ellos (que no necesariamente sabe si un envoltorio también necesita liberar recursos).
try (InputStream inputStream = new URL(url).openStream();
ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream);
FileOutputStream fileOutputStream = new FileOutputStream(Bukkit.getServer().getUpdateFolderFile());
FileChannel fileChannel = fileOutputStream.getChannel()) {
fileChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
} catch (IOException ex) {
ex.printStackTrace();
}
Lo anterior no es muy diferente de lo que tiene actualmente.
1. Llamar a Closeable#close()
método no tiene ningún efecto si se invoca con anterioridad. Esto no es necesariamente cierto de AutoCloseable
implementaciones (que no aplicar Closeable
).
Además, si usted está usando Java 9+ no es necesario para hacer frente a los canales NIO. La InputStream
clase había añadido un método en Java 9: transferTo(OutputStream)
.
try (InputStream is = new URL(url).openStream();
FileOutputStream fos = new FileOutputStream(...)) {
is.transferTo(fos);
} catch (IOException ex) {
ex.printStackTrace();
}
También podría ser capaz de utilizar Files.copy(InputStream,Path,CopyOption...)
(Java 7+).
try (InputStream is = new URL(url).openStream()) {
Path file = Bukkit.getServer().getUpdateFolderFile().toPath();
Files.copy(is, file, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
ex.printStackTrace();
}
Tenga en cuenta que esto podría no resultar en el mismo comportamiento que cuando se utiliza FileOutputStream
. No estoy del todo seguro de si FileOutputStream#<init>(File)
Trunca los bytes existentes o si simplemente sobrescribe los bytes desde el principio.
Si prefiere utilizar canales NIO, puede abrir una FileChannel
directamente a través FileChannel.open(Path,OpenOption...)
en lugar de ir a través de una FileOutputStream
. Como he mostrado en el ejemplo anterior, se puede convertir una File
en una Path
utilizando File#toPath()
.