Закрытие потоков / сокетов и try-catch-finally - PullRequest
5 голосов
/ 17 мая 2011

Вот пример, по которому у меня есть вопросы (это происходит из другого 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 в секции finally try-catch-finally?Конечно, я мог бы просто поместить код последовательно после try-catch?

  2. Почему я должен закрывать FileOutputStream отдельно, а не просто заменить new OutputStreamWriter(fos, ... на new OutputStreamWriter(new FileOutputStream(filename), ...?Если я сначала закрою FileOutputStream, это автоматически закроет остальные и освободит ресурсы?Те же вопросы применимы к сокетам, если я закрываю сокетное соединение, автоматически ли закрываются потоковые считыватели / записи и освобождаются ресурсы?

  3. Мне неоднократно говорили, чтобы я читалзаписывать потоки с "UTF-8" из-за того, что разные системы имеют разные кодировки (или что-то в этом роде).Это все еще применимо при чтении / записи байтовых данных RAW (скажем, из нетекстового файла или в результате шифрования), как я думал в кодировках, где делать только с текстовыми символами?

Ответы [ 4 ]

6 голосов
/ 17 мая 2011
  1. Поскольку, если ваш код выдает необработанное исключение, фрагмент после блока try-catch не будет выполнен.Например, в случае NullPointerExcpetion.

  2. Вам не нужно.Если вы закроете поток, любой из его вложенных потоков также будет закрыт.

  3. Нет.Это имеет место только при преобразовании байтов в символы (или наоборот).Вы указываете кодировку для OutputStreamWriter, которая отвечает за преобразование символов в байты.

1 голос
/ 17 мая 2011

почему я должен закрывать FileOutputStream в разделе finally в try-catch-finally?

Вы можете поставить 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.

0 голосов
/ 17 мая 2011
  1. Часто в блоке catch кто-то создает исключение RuntimeException, которое вызывает возврат этого метода. Если вы не очистите свои ресурсы в конечном итоге, они не будут очищены. В вашем примере у вас должно получиться хорошее закрытие после блока finally, потому что вы не форсируете свой выход.
  2. Вызов close () для потока-оболочки должен закрыть дочерний поток. Если вы пишете свой собственный поток-обертку, его метод close должен делегировать close () его дочерним элементам. Вот почему я должен сказать, что реализация должна вызывать close () для своих дочерних элементов.
  3. Если вы пишете необработанные байтовые данные, вам не нужно указывать utf-8. Это кодировка символов, помогающая отображать символы на разных языках.
0 голосов
/ 17 мая 2011

По первому пункту - если ваш код выдал ошибку, а не исключение, FileOutputStream не был бы закрыт, если бы оператор close не был в finally. В вашем случае это немного искусственно, так как вы ловите Exception, но в более типичной ситуации, когда будет поймано более конкретное исключение, если вы не приведете в порядок ресурсы в блоке finally, выполнение метода может прекратиться до того, как он достигнет код, который закроет ресурсы.

...