应该关闭哪些资源?

时间:2019-06-16 10:48:01

标签: java file download

我正在尝试从URL下载文件。有很多资源,我不知道我需要关闭哪一个资源,还是我只需要关闭所有资源?

    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();
    }
}

3 个答案:

答案 0 :(得分:3)

对于您来说, 需要关闭的唯一资源可能是InputStreamFileOutputStream。但是,为什么不简单地使用try-with-resources将它们全部关闭呢?以防万一 1 调用Closeable#close()并没有什么害处。实际上,完成操作后,您可能应该关闭控件中的每个Closeable(即,您打开的它们)(您不一定知道包装程序是否也需要释放资源)。

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();
}

以上内容与您目前所拥有的并没有太大区别。


1。如果先前已调用,则调用Closeable#close()方法无效。对于AutoCloseable实现(未实现Closeable),不一定是正确的。


此外,如果您使用的是Java 9+,则不需要处理NIO通道。 InputStream类在Java 9中添加了一个方法:transferTo(OutputStream)

try (InputStream is = new URL(url).openStream();
     FileOutputStream fos = new FileOutputStream(...)) {
    is.transferTo(fos);
} catch (IOException ex) {
    ex.printStackTrace();
}

您也许还可以使用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();
}

请注意,这可能导致与使用FileOutputStream时不同的行为。我不确定FileOutputStream#<init>(File)是否会截断任何现有字节,还是只是从头开始覆盖字节。

如果您更喜欢使用NIO通道,则可以直接通过FileChannel.open(Path,OpenOption...)打开FileChannel,而不用通过FileOutputStream。如上例所示,您可以使用FilePath转换为File#toPath()

答案 1 :(得分:0)

对于您来说,关闭FileChannel应该足够了,它将关闭parent或相应资源的FileDescriptor(请参阅java11 sources)。实际上,以相同的结果,您只能关闭fileOutputStream,它也将释放所有文件资源(source code

但是,由于您依赖于这些可关闭资源的实现,因此最佳实践是关闭您打开的每个资源,更简单的方法是使用{{3 }}。

答案 2 :(得分:0)

谢谢大家,因为我使用的是Java 8,所以我可能要使用Files.copy(InputStream输入,Path目标,CopyOption ...选项),然后关闭InputStream。否则我会用InputStream#transferTo(OutputStream out)。