Closing streams/sockets and try-catch-finally

2019-06-21 05:24发布

Here is an example I have questions about (it comes from another SO question):

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.");
            }
        }
    }
}

Now I think this code works fine and releases all the resources where it should etc. My questions are:

  1. Why should I be closing the FileOutputStream in the finally section of the try-catch-finally? Surely I could just put the code sequentially after the try-catch?

  2. Why must I close the FileOutputStream separately rather than simply replacing new OutputStreamWriter(fos, ... with new OutputStreamWriter(new FileOutputStream(filename), ...? If I close the FileOutputStream first, will that automatically close the rest and release the resources? Same questions apply for sockets, if I close a socket connection does that automatically close the stream readers/writers and release the resources?

  3. I've been told repeatedly to ensure that I read and write streams with "UTF-8" due to different systems having different charsets (or something along those lines). Is this still applicable when reading/writing RAW byte data (say from a non-text file, or the result of an encryption) as I thought charsets where to do with textual characters only?

4条回答
beautiful°
2楼-- · 2019-06-21 05:55
  1. Often, in a catch block, someone will throw a RuntimeException, which will cause this method to return. If you do not clean up your resources in the finally, they will not be cleaned up. In your example, you should be fine closing after the finally block, because you are not forcing your way out.
  2. Calling close() on a wrapper stream should close the child stream. If you write your own wrapper stream, its close method should delegate the close() to its children. This is why I say should, it is up to the implementer to call close() on its children.
  3. If you are writing raw byte data, you should not need to specify utf-8. It is a character encoding to help display characters in various languages.
查看更多
霸刀☆藐视天下
3楼-- · 2019-06-21 05:59

why should I be closing the FileOutputStream in the finally section of the try-catch-finally?

You can put the close() at the end of all the writing/reading operations block, but if something goes wrong while in there(reading/writing), you'll reach the exception handling block and no stream will be closed. If you choose to put the close() in the exception handling block and everything goes fine, guess what?... no stream will be closed. So you can do it in both blocks of code, but that way the code will be less readable. So putting it on the finally block assures you that either way it will be closed.

Second, you should close only the last stream that has been chained. so if you have this.

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

You only need to

out.close();

That will close the other streams associated to the out stream.

The UTF-8 part depends on the type of data encoding you're trying to read, if you encode UTF-8, decode UTF-8.

查看更多
SAY GOODBYE
4楼-- · 2019-06-21 06:12
  1. Because if your code throw an un-handled exception, the snippet after the try-catch bloc will never gets executed. This is the case with NullPointerExcpetion, for example.

  2. You don't have to. If you close a stream, any of its enclosed streams will be closed as well.

  3. No. This is the case only when converting bytes to characters (or the other way around). You're specifying the charset to the OutputStreamWriter, which is responsible for converting characters to bytes.

查看更多
Evening l夕情丶
5楼-- · 2019-06-21 06:12

On the first point - if your code threw an error, rather than an exception the FileOutputStream would not be closed if the close statement was not in the finally. It's a little artificial in your case as you are catching Exception, but in a more typical situation where a more specific exception would be caught, unless you tidy up the resources in the the finally block, execution of the method may terminate before it reaches the code that will close the resources.

查看更多
登录 后发表回答