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