【问题标题】:Closing resource coming as return from method关闭作为方法返回的资源
【发布时间】:2020-12-17 15:32:40
【问题描述】:

我有一个带有返回流的静态方法的辅助类:

public static InputStream getDocument(File file) throws IOException {
    ZipFile zipFile = new ZipFile(file);
    return zipFile.getInputStream(zipFile.getEntry("entry"));
}

另一个类访问该方法并使用返回的流:

InputStream is = MyClass.getDocument(new File(str));

我的代码有效。


但是,according to the Java Documentation, 我应该关闭我的资源:

资源是程序完成后必须关闭的对象。 try-with-resources 语句确保每个资源在语句结束时关闭。

但是,当我实现try-with-resources:

public static InputStream getDocument(File file) throws IOException {
    try (ZipFile zipFile = new ZipFile(file);) {
        return zipFile.getInputStream(zipFile.getEntry("entry"));
    }
}

try-finally:

public static InputStream getDocument(File file) throws IOException {
    InputStream is = null;
    try {
        ZipFile zipFile = new ZipFile(docx);
        is = zipFile.getInputStream(zipFile.getEntry("entry"));
        return is;
    } finally {
        is.close();
    }
}

我得到一个例外:

java.io.IOException: Stream closed

如何确保该资源将在使用后被关闭?

【问题讨论】:

标签: java inputstream autocloseable


【解决方案1】:

通常调用者负责关闭/释放资源。
您可以在方法外部使用 try-with-resourcetry-finally 构造,如下所示:

try (InputStream is = getDocument(aFile) {
    //… do your stuff
}

如果我能给你一个建议,请写在方法文档中:

/**
  * The caller is required to close the returned {@link InputStream}
  */
public static InputStream getDocument(File file) throws IOException

【讨论】:

  • 我注意到,SonarQube 将其限定为错误,我的资源没有直接在方法中关闭。这就是为什么我想知道...
  • SonarQube 中似乎是误报。几天前我看到了类似的问题
  • 如果你们在谈论这个,jira.sonarsource.com/browse/SONARJAVA-2060 现在应该修复了
【解决方案2】:

try-with-resources 与您使用finally 的第二种方法隐含相同。没有办法关闭 zipFile,而是根据这个 zipFile 返回一个 inputStream。

通常最好避免使用这种辅助方法并使用具有多个资源的单个 try-with-resourcerces:

try (
   ZipFile zipFile = new ZipFile(file);
   inputStream inputStream = zipFile.getInputStream(zipFile.getEntry("entry"));
) {
    // Do stuff
} // Both zipFile and inputStream closed here implicitly

如果您需要创建这样的方法,但是您可以确保当流关闭时,zipFile 对象也被关闭。

来自相关问题Does a ZipEntry persist after a ZipFile is closed?

zipFile = new ZipFile(file);
InputStream zipInputStream = ...
return new InputStream() {
    @Override
    public int read() throws IOException {
        return zipInputStream.read();
    }
    @Override
    public void close() throws IOException {
        // Better add try/catch around each close()
        zipInputStream.close();
        zipFile.close();
    }
}

这样,当调用方法关闭它接收到的流时,压缩文件也将被关闭。

【讨论】:

  • 这两个问题唯一的共同点是“Stream”这个词
  • 没有细微的差别,这个问题是关于返回的流被过早关闭但在你提到的问题中。这是关于确保关闭用于创建(字符串)流的资源。
  • 我在乎,因为您投票结束了这个问题,并且还提供了一个没有完全解决问题的答案。
  • 我已经完全改变了我的答案并将其变成了社区维基。随意使用它,尽管接受的答案可能会获得更多视图。
猜你喜欢
  • 2018-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-12
  • 2017-10-02
  • 2021-09-08
  • 2014-01-30
  • 1970-01-01
相关资源
最近更新 更多