Как правильно открыть поток в Java? - PullRequest
3 голосов
/ 01 апреля 2012

Я буду читать лекцию по Java для студентов-физиков, и я хотел бы знать, как правильно открыть файл.

Во многих моих профессиональных приложениях я делал что-то подобное:

  BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("file")));
  try{
    ....
  }finally {
     bufferedWriter.close();
  }

что имхо нормально, т.е. читатель всегда будет закрыт.

Когда я описывал это в качестве примера для моих учеников, мне было интересно, что произойдет, если конструктор InputStreamReader сгенерирует исключение --- FileInputStream будет открыт, но он не будет закрыт моим кодом (так как эти объекты создаются вне блока try-finally.

Так это правильная идиома, и если да, то почему? Если неправильно открывать поток, пожалуйста, укажите мне правильный!

Редактировать : Я ищу идиому, которая является правильной и очень простой для написания и понимания , студенты-физики - новички в программировании.

Редактировать : Глупый я, я скопировал неправильный пример - если вместо читателей я использую Writers, это становится более сложным.

Ответы [ 2 ]

4 голосов
/ 01 апреля 2012

Чтение с входных потоков

До Java 7 так вы и делали

InputStream in = null;
try {
     in = new FileInputStream("simple.csv");
     BufferedReader buf = new BufferedReader(new InputStreamReader(in));
} finally {
  if (in != null) {
     try {
         in.close();
     } catch (IOException e) {}
  }
}

Для Java 7 вы можете использовать Closeable, что-то вроде

try (BufferedReader buf = new BufferedReader(...)) {}

РЕДАКТИРОВАТЬ: Почему я не закрыл buf выше? Посмотрите исходный код для BufferedReader.close()

public void close() throws IOException {
    synchronized (lock) {
        if (in == null)
            return;
        in.close();
        in = null;
        cb = null;
    }
}

Запись с выходными потоками

РЕДАКТИРОВАТЬ 2: Тот же принцип применяется к писателей . Однако, если вы действительно заинтересованы в очистке потока, когда происходит IOException, то вы должны проверить writer и stream для null и попытаться закрыть их соответственно. Это, тем не менее, дает много дополнительного кода. Это может выглядеть примерно так:

BufferedWriter buf = null;
OutputStream out = null;
try {
    out = new FileOutputStream("file");
    buf = new BufferedWriter(new OutputStreamWriter(out));
} finally {
  if (buf != null) {
     try { buf.close(); } catch (IOException ex){}
  }
  if (out != null) {
     try { out.close(); } catch (IOException ex){}
  }
}

Это не очень красиво. Вы можете ввести вспомогательную подпрограмму для закрытия ваших потоков или изучить Java 7 или Apache IOUtils

0 голосов
/ 01 апреля 2012

В этом особом случае (вложенные конструкторы) FileInputStream останется открытым. Вам придется сделать это следующим образом (если вам действительно нужно убедиться, что поток закрыт):

final FileInputStream fis = new FileInputStream("");
try
{
    final BufferedReader br = new BufferedReader(new InputStreamReader(fis));
    // ...
}
finally
{
    fis.close();
}

Закрытие FileInputStream должно быть достаточным.

Редактировать: та же логика может быть применена к писателям. Если открытие FileOutputStream завершается неудачно, генерируется исключение, которое не позволяет выполнить блок try / finally. И если любой другой конструктор писателя завершается неудачно, выходной поток все еще закрывается с помощью предложения final.

...