文件io-Java io ugly-finally b

有没有那么丑陋的方式来处理close()96异常以关闭两个流,然后:

    InputStream in = new FileInputStream(inputFileName);
    OutputStream out = new FileOutputStream(outputFileName);

    try {
        copy(in, out);
    } finally {
        try {
            in.close();
        } catch (Exception e) {
            try {
                // event if in.close fails, need to close the out
                out.close();
            } catch (Exception e2) {}
                throw e; // and throw the 'in' exception
            }
        }
        out.close();
    }

更新:以上所有代码都在一个try-catch中,感谢您的警告。

最后(答案之后):

而且,可以使用Execute Around惯用语来实现良好的实用方法(感谢Tom Hawtin)。

Tom Brito asked 2020-07-23T20:22:45Z
12个解决方案
54 votes

这是正确的习惯用法(很好用):

   InputStream in = null;
   OutputStream out = null;
   try {
       in = new FileInputStream(inputFileName);
       out = new FileOutputStream(outputFileName);
       copy(in, out);
   finally {
       close(in);
       close(out);
   }

  public static void close(Closeable c) {
     if (c == null) return; 
     try {
         c.close();
     } catch (IOException e) {
         //log the exception
     }
  }

之所以能正常工作,是因为只要您的finally代码本身不会引发异常或以其他方式异常终止,那么在您最终到达之前引发的异常将在您的finally代码完成之后引发。

编辑:从Java 7(和Android SDK 19-KitKat)开始,现在有Try with resources语法,可以使此工具更加简洁。 这个问题解决了如何处理。

Yishai answered 2020-07-23T20:23:05Z
32 votes

您可以实现一个实用程序方法:

public final class IOUtil {
  private IOUtil() {}

  public static void closeQuietly(Closeable... closeables) {
    for (Closeable c : closeables) {
        if (c != null) try {
          c.close();
        } catch(Exception ex) {}
    }
  }
}

然后,您的代码将简化为:

try {
  copy(in, out);
} finally {
  IOUtil.closeQuietly(in, out);
}

额外

我想在第三方开源库中会有这样的方法。 但是,我的首选是避免不必要的库依赖性,除非我使用了大部分功能。 因此,我倾向于自己实现像这样的简单实用程序方法。

Adamski answered 2020-07-23T20:23:39Z
18 votes
try {
    final InputStream in = new FileInputStream(inputFileName);
    try {
        final OutputStream out = new FileOutputStream(outputFileName);    
        try {
            copy(in, out);
            out.flush(); // Doesn't actually do anything in this specific case.
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
} catch (IOException exc) {
    throw new SomeRelevantException(exc);
}

请记住,打开流可能会引发异常,因此在流开口之间确实需要transferTo(请不要进行涉及transferFrom的改动。任何事情都可以抛出try(这不是Exception的实例)。

结果表明transferTotransferFrom应该很少共享相同的try

从Java SE 7开始,您可以编写使用try-with-resource来避免太多缩进。 尽管隐藏了被抑制的异常,但它或多或少地做了同样的事情。

try (
    final InputStream in = new FileInputStream(inputFileName);
    final OutputStream out = new FileOutputStream(outputFileName);    
) {
    copy(in, out);
    out.flush(); // Doesn't actually do anything in this specific case.
} catch (IOException exc) {
    throw new SomeRelevantException(exc);
}

您可能需要使用Execute Around习语。

我相信复制的标准好方法是使用NIO的transferTo/transferFrom

Tom Hawtin - tackline answered 2020-07-23T20:24:17Z
8 votes

Guava具有非常好的IO API,因此无需这样做。 例如,您的示例将是:

Files.copy(new File(inputFileName), new File(outputFileName));

更一般而言,它使用Closeables.closeQuietly(Closeable)s和OutputSuppliers的概念允许在其实用工具方法中创建2979602899694781781442s和OutputStreams,从而使其能够完全控制它们,从而可以正确处理关闭操作。

此外,它具有Closeables.closeQuietly(Closeable),这基本上是大多数答案所建议的方法类型。

其中的IO内容仍处于测试阶段,并且可能会发生变化,但是值得一试甚至使用,具体取决于您正在处理的内容。

ColinD answered 2020-07-23T20:24:51Z
7 votes

我坚信,在Java 7.0中,您不再需要自己显式关闭流。 Java 7中的语言功能

try (BufferedReader br = new BufferedReader(new FileReader(path)) {
   return br.readLine();
}
vodkhang answered 2020-07-23T20:25:11Z
7 votes

从Java 7开始,有一种更好的方式来编写关于for资源的try-finally块。

现在,您可以在for关键字后的括号中创建资源,如下所示:

try (initialize resources here) {
   ...
}

代码块完成后,它们将自动关闭。 不需要for零件。

一个例子:

try (
   ZipFile zf = new ZipFile(zipFileName);
   BufferedWriter writer = Files.newBufferedWriter(outputFilePath, charset);
) {
    // Enumerate each entry
    for (Enumeration entries = zf.entries(); entries.hasMoreElements();) {
        // Get the entry name and write it to the output file
        String newLine = System.getProperty("line.separator");
        String zipEntryName = ((java.util.zip.ZipEntry)entries.nextElement()).getName() + newLine;
        writer.write(zipEntryName, 0, zipEntryName.length());
    }
}

for循环完成之后,资源将被关闭!

darijan answered 2020-07-23T20:25:48Z
5 votes

在IOUtils中,共有一点,就是某些closeQuietly方法。

Istao answered 2020-07-23T20:26:08Z
2 votes

我有时使用的一个技巧是定义一个名为try的方法,该方法进行测试以查看其参数是否为null,然后将其关闭,而忽略任何异常。 但是您需要谨慎地关闭OutputStreams和Writers,因为它们实际上可能引发重要的异常。 例如 如果最终冲洗失败。

Java 7可能会改善情况。据报道,它将拥有一个新的结构,该结构提供了一种更为简洁的方式来管理托管资源。 例如 完成时需要关闭的流。

最后,您应该意识到您的示例存在错误。 如果该方法调用打开第二个流,则第一个流将不会关闭。 第二次打开需要在try模块内部完成。

Stephen C answered 2020-07-23T20:26:38Z
1 votes

在大多数情况下,“ in” close()异常是无关紧要的,因此:

    try {
      copy(in, out);
    } finally {
    try {  in.close()  }  catch (Exception e) { /* perhaps log it */ }
    try {  out.close() }  catch (Exception e) {/* perhaps log it */ }
    } 

吞下异常通常是不好的做法,但在这种情况下,我认为可以。

leonbloy answered 2020-07-23T20:27:02Z
0 votes

IOUtils.closeNoThrow(myInputStream);

简洁大方。

user3402937 answered 2020-07-23T20:27:26Z
0 votes

这是我的答案,希望会更好

[HTTPS://stack overflow.com/啊/35623998/2585433]

try {
    fos = new FileOutputStream(new File("..."));
    bos = new BufferedOutputStream(fos);
    oos = new ObjectOutputStream(bos);
}
catch (Exception e) {
}
finally {
    Stream.close(oos,bos,fos);
}


class Stream {

public static void close(AutoCloseable... array) {
    for (AutoCloseable c : array) {
        try {c.close();}
        catch (IOException e) {}
        catch (Exception e) {}
    }
  } 
}
Noor Nawaz answered 2020-07-23T20:27:50Z
-2 votes

在C#中,当我们离开范围时,有using构造会自动关闭可关闭的对象:

using(Stream s = new Stream(filename)) {
  s.read();
}

我认为这是java的try-finally块的简短形式。 Java 6引入了Closable接口。 因此,using几乎在那里。 当最后一步在Java 7中完成时,确实很棒。

Val answered 2020-07-23T20:28:15Z
translate from https://stackoverflow.com:/questions/2699209/java-io-ugly-try-finally-block