Закрытие InputStream закрывает канал, связанный с ним? - PullRequest
1 голос
/ 09 марта 2020

Если я создам Channel из InputStream, а затем закрою InputStream, закроет ли он связанный Channel? Нужно ли явно закрывать связанный Channel? Я знаю, что закрытие канала закроет поток, но как быть с обратным?

try (InputStream ioStream = getInputStream()) {
    ReadableByteChannel inputChannel = Channels.newChannel(ioStream);
    //do something
} 

Ответы [ 4 ]

1 голос
/ 09 марта 2020

В общем случае InputStream ничего не знает о Channel, поэтому закрытие InputStream не может автоматически закрыть Channel.

Однако, пытаясь чтение из Channel после закрытия InputStream вызовет IOException:

  • , канал должен получать данные из входного потока через InputStream.getBytes()
  • InputStream.getBytes() выдаст IOException, если входной поток был закрыт.

Для особого случая FileInputStream вызов Channels.newChannel(ioStream) вернет FileInputStream.getChannel(), поэтому в этом специальный случай закрытия входного потока также закроет канал.

0 голосов
/ 09 марта 2020

Рассматривая реализацию Channels.newChannel:

    public static ReadableByteChannel newChannel(InputStream in) {
        Objects.requireNonNull(in, "in");

        if (in.getClass() == FileInputStream.class) {
            return ((FileInputStream) in).getChannel();
        }

        return new ReadableByteChannelImpl(in);
    }

Как видите, если входной поток является потоком файлов, у нас есть особый случай. В этом особом случае метод close() результирующего канала просто вернет ! checked, где checked - это приватное логическое поле входного потока соответствующего файла. Когда вы закрываете поток ввода файла, он устанавливает closed в значение true, а затем канал также будет думать, что он закрыт:

   InputStream is = new FileInputStream(new File("test.file"));
   ReadableByteChannel channel = Channels.newChannel(is);
   System.out.println(channel.isOpen());  // True
   is.close();
   System.out.println(channel.isOpen());  // False

Однако это деталь реализации, поэтому вы не можете полагаться на Это. Кроме того, если поток ввода не является потоком ввода файла, то приведенное выше не будет работать вообще.

0 голосов
/ 09 марта 2020

Из Java API 7:

Полученный канал не будет буферизован; он просто перенаправит свои операции ввода-вывода в данный поток. Закрытие канала в свою очередь приведет к закрытию потока .

Надеюсь, это поможет!

0 голосов
/ 09 марта 2020

Я предполагаю, что суть вашего беспокойства в том, что у вас нет "утечки", если ресурсы остаются открытыми.

Насколько я знаю, пока основной ресурс закрывается, вы выиграли нет утечки, поскольку этот базовый объект (с нативными методами) - это то, что говорит с ОС и поддерживает ресурс открытым.

Поскольку в документации сказано, что он просто перенаправляет в поток (я выделил жирным шрифтом) затем закрытие самого InputStream закроет единственный фактический ресурс, так как Channel.newChannel(InputStream) не создает новый ресурс.

Я бы, однако, лучше открыл ваш канал в попытке с ресурсами и позволил ему быть закрывается автоматически, что приведет к каскадному подключению к базовому ресурсу.

Пользователь Slaw имеет правильную идею о том, что InputStream ничего не знает о канале (за исключением особого случая FileInputStream, как показано Алексом) , Это одна из причин, по которой вам следует закрывать ресурсы оболочки, а не , а просто базовые ресурсы, чтобы ваши оболочки имели постоянные знания о реальном ресурсе.


java .nio.channels.Channels.newChannel (InputStream) - Java 1.8 API

Создает канал, который читает байты из данного потока .

Полученный канал не будет буферизован; он просто перенаправит свои операции ввода-вывода в указанный поток . Закрытие канала, в свою очередь, приведет к закрытию потока.

Параметры:
in - Поток, из которого считываются байты

Возвращает:
Новый читаемый байтовый канал

...