I'm trying to download a file from an URL. There are many resources and I dont know which one I need to close or do I simply have to close all of them?
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();
}
}
In your case, likely the only resources that need to be closed are the InputStream and FileOutputStream. However, why not simply close them all by using try-with-resources? It doesn't hurt to call Closeable#close() just in case1. In fact, you probably should close every Closeable in your control (i.e. that you opened) when finished with them (you don't necessarily know if a wrapper also needs to release resources).
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();
}
The above is not much different than what you currently have.
1. Calling Closeable#close() method has no effect if invoked previously. This isn't necessarily true of AutoCloseable implementations (that don't implement Closeable).
Also, if you're using Java 9+ you don't need to deal with NIO channels. The InputStream class had a method added in Java 9: transferTo(OutputStream).
try (InputStream is = new URL(url).openStream();
FileOutputStream fos = new FileOutputStream(...)) {
is.transferTo(fos);
} catch (IOException ex) {
ex.printStackTrace();
}
You might also be able to use 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();
}
Note this might not result in the same behavior as when using FileOutputStream. I'm not entirely sure if FileOutputStream#<init>(File) truncates any existing bytes or if it simply overwrites the bytes from the beginning.
If you prefer using NIO channels, you can open a FileChannel directly via FileChannel.open(Path,OpenOption...) rather than going through a FileOutputStream. As I showed in an example above, you can convert a File into a Path using File#toPath().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With