关闭流/套接字和try-catch-finally

时间:2011-05-17 14:49:29

标签: java sockets character-encoding io try-catch

这是一个我有疑问的例子(来自另一个SO问题):

public static void writeToFile (final String filename)
{
    PrintWriter out = null;     
    FileOutputStream fos = null;

    try
    {
        fos = new FileOutputStream(filename);
        out = new PrintWriter(new BufferedWriter(
                              new OutputStreamWriter(fos, "UTF-8")));

        for (final String line : log)
        {
            out.println(line);
        }

        out.flush();
        out.close();
    }
    catch (final Exception e)
    {
        System.err.println("Unable to write log to file.");
    }
    finally
    {
        if (fos != null)
        {
            try
            {
                fos.close();
            }
            catch (final IOException e)
            {
                System.err.println("Unable to write log to file.");
            }
        }
    }
}

现在我认为这段代码工作正常并释放所有应该使用的资源等等。我的问题是:

  1. 为什么要关闭FileOutputStream的{​​{1}}部分中的finally?当然,我可以在try-catch-finally

  2. 之后按顺序放置代码
  3. 为什么我必须单独关闭try-catch而不是简单地用FileOutputStream替换new OutputStreamWriter(fos, ...?如果我先关闭FileOutputStream,会自动关闭其余部分并释放资源吗?同样的问题适用于套接字,如果我关闭套接字连接会自动关闭流读取器/编写器并释放资源吗?

  4. 我一再被告知要确保我使用“UTF-8”读取和写入流,因为不同的系统具有不同的字符集(或沿着这些行的东西)。这是否仍然适用于读取/写入RAW字节数据(例如,来自非文本文件,或加密的结果),因为我认为charsets只与文本字符有关?

4 个答案:

答案 0 :(得分:6)

  1. 因为如果你的代码抛出一个未处理的异常,那么try-catch bloc之后的代码段永远不会被执行。例如NullPointerExcpetion就属于这种情况。

  2. 你不必。如果您关闭一个流,它的任何封闭流也将被关闭。

  3. 没有。仅在将字节转换为字符(或相反)时才是这种情况。您正在为OutputStreamWriter指定字符集,该字符集负责将字符转换为字节。

答案 1 :(得分:1)

我为什么要关闭try-catch-finally的finally部分中的FileOutputStream?

您可以将close()放在所有写入/读取操作块的末尾,但如果在那里出现问题(读/写),您将到达异常处理块,没有流将被关闭如果您选择将close()放在异常处理块中并且一切正常,请猜猜是什么?...将不会关闭任何流。所以你可以在两个代码块中完成它,但这样代码的可读性就会降低。因此,将它放在finally块上可以确保它将以任何方式关闭。

其次,您应该只关闭已链接的最后一个流。所以,如果你有这个。

fos = new FileOutputStream(filename);
        out = new PrintWriter(new BufferedWriter(
                              new OutputStreamWriter(fos, "UTF-8")));

你只需要

out.close();

这将关闭与出口相关联的其他流。

UTF-8部分取决于您尝试读取的数据编码类型,如果您编码UTF-8,则解码UTF-8。

答案 2 :(得分:0)

在第一点 - 如果你的代码抛出错误而不是异常,如果close语句不在finally中,则不会关闭FileOutputStream。在你捕获异常时,你的情况有点人为,但是在更典型的情况下会捕获更具体的异常,除非你整理finally块中的资源,方法的执行可能会在它到达之前终止。将关闭资源的代码。

答案 3 :(得分:0)

  1. 通常,在catch块中,有人会抛出RuntimeException,这将导致此方法返回。如果你没有清理你的资源,他们将不会被清理。在你的例子中,你应该在finally块之后关闭,因为你没有强迫你出路。
  2. 在包装器流上调用close()应该关闭子流。如果你编写自己的包装器流,它的close方法应该将close()委托给它的子节点。这就是为什么我应该说,应该由实现者来调用它的子节点上的close()。
  3. 如果要编写原始字节数据,则不需要指定utf-8。它是一种字符编码,可帮助显示各种语言的字符。