【问题标题】:Sonar violation: "Method may fail to close stream on exception"声纳违规:“方法可能无法在异常时关闭流”
【发布时间】:2012-09-04 10:13:06
【问题描述】:

我有这个方法:

 private void unZipElementsTo(String inputZipFileName, String destPath) throws FileNotFoundException, IOException {

        OutputStream out = null;
        InputStream in = null;
        ZipFile zf = null;

        try {
            zf = new ZipFile(inputZipFileName);

            for (Enumeration<? extends ZipEntry> em = zf.entries(); em.hasMoreElements();) {
                ZipEntry entry = em.nextElement();
                String targetFile = destPath + FILE_SEPARATOR + entry.toString().replace("/", FILE_SEPARATOR);
                File temp = new File(targetFile);

                if (!temp.getParentFile().exists()) {
                    temp.getParentFile().mkdirs();
                }

                in = zf.getInputStream(entry);

                out = new FileOutputStream(targetFile);
                byte[] buf = new byte[4096];
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                out.flush();
                out.close();
                in.close();
            }
        }
        finally
        {
            if (out!=null) out.close();
            if (zf!=null) zf.close();
            if (in!=null) in.close();
        }
    }

对于这个方法,Sonar 给我这个违规:

不好的做法 - 方法可能无法在异常时关闭流 unZipElementsTo(String, String) 可能无法在异常时关闭流

但是,我没有看到任何违规行为。也许,它只是一个假阳性?

【问题讨论】:

    标签: java exception inputstream sonarqube


    【解决方案1】:

    没错。 OutputStream.close() 方法本身可以抛出异常。 如果发生这种情况,例如在finally{} 块的第一行,其他流将保持打开状态。

    【讨论】:

    • 一个好的做法是使用特殊的实用方法静默关闭流,即关闭或吞下异常,因为无论如何您都无法从此类异常中恢复:public static closeSilently(OutputStream os) { try { os.close(); } 捕捉(IOException ex){} }
    • IOException on stream close 可能表示该文件未写入磁盘。让它传播比默默地忽略它要安全得多。
    【解决方案2】:

    如果finally 块中的out.close()zf.close() 抛出异常,则不会执行其他关闭。

    【讨论】:

    • 能否提供快速修复的建议?
    【解决方案3】:

    或者,如果您使用的是 Java 7 或更高版本,则可以使用新的 try-with-resources 机制,它会为您处理关闭。有关此新机制的详细信息,请参阅:http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

    请注意,try-with-resources 也适用于打开和关闭的多个对象,并且仍然保证对象将以与其构造相反的顺序关闭。引用同一页面:

    请注意,资源的关闭方法的调用顺序与它们的创建顺序相反。

    【讨论】:

      【解决方案4】:

      为了避免在流关闭期间用异常掩盖异常 通常建议在 finally 中“隐藏”任何 io 异常。

      要修复使用 org.apache.commons.io.IOUtils.closeQuietly(...) 或番石榴 Closeables.html#closeQuietly(java.io.Closeable) 在终于关闭

      更多关于异常处理问题:
      http://mestachs.wordpress.com/2012/10/10/through-the-eyes-of-sonar-exception-handling/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-01
        • 2011-09-12
        • 2013-09-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多