Подтвердить что ты не робот

Почему невозможно открыть закрытый (стандартный) поток?

System.in - это "стандартный" входной поток, который поставляет пользовательские входные данные. После закрытия этот поток не может быть повторно открыт. Одним из таких примеров является использование сканера для чтения пользовательского ввода следующим образом:

public class Test {
    public static void main(String[] args) {

        boolean finished;

        do {
            Scanner inputScanner = new Scanner(System.in);
            finished = inputScanner.hasNext("exit");
            boolean validNumber = inputScanner.hasNextDouble();
            if (validNumber) {
                double number = inputScanner.nextDouble();

                System.out.print(number);
            } else if (!finished) {
                System.out.println("Please try again.");
            }
            inputScanner.close();
        } while (!finished);
    }
}

В этом примере создается экземпляр типа Scanner и используется для чтения серии чисел от пользователя (просьба игнорировать другие данные с помощью этого кода, выходящего за рамки этого примера, я знаю, что сканер должен быть созданный и закрытый вне цикла). После получения номера из пользовательского ввода экземпляр этого Scanner (т.е. Входной поток) закрыт. Однако, когда другой запрос запрашивается у пользователя и создается новый экземпляр, входной поток не может быть снова открыт. В случае этого примера он создает бесконечный цикл.

Возникает вопрос: почему невозможно открыть закрытый поток?

4b9b3361

Ответ 1

почему невозможно открыть закрытый поток в Java?

Просто природа базовой операционной системы создает потоки Java. Поток по существу является каналом передачи данных. Когда вы закроете его, его больше не будет. Возможно, вы сможете создать новую между одними и теми же конечными точками, но это дает принципиально другой поток. Мы могли бы рассмотреть такие аспекты реализации, как буферизация и позиционирование потоков, но это действительно проблемы.

Вы также задали вопрос о стандартных потоках. Это некоторые из случаев, которые вы не можете воссоздать. Операционная система предоставляет каждому процессу набор стандартных потоков. Как только они закрыты, невозможно получить эквиваленты. Вы можете разместить разные потоки на своем месте, но вы не можете подключить их к исходным конечным точкам.

Ответ 2

Когда вы закрываете стандартный поток ввода:

  • Если ваш вход был предоставлен трубкой, другой конец трубы уведомляется. Он закроет свой конец и прекратит отправку данных. Невозможно сказать, что вы допустили ошибку, и она должна снова начать отправку;

  • Если ваш вход был предоставлен файлом, ОС отбрасывает ссылку на файл и полностью забывает, что вы его использовали. Вам просто не предоставляется возможность повторно открыть стандартный ввод и продолжить чтение;

  • Если ваш вход был предоставлен консолью, он работает с каналом. Консоль будет уведомлена, закроет ее конец и перестанет отправлять вам данные.

Таким образом, нет возможности повторно открыть стандартный ввод.

НО... также нет причин закрывать стандартный ввод, поэтому просто не делайте этого!

Хорошим примером для этого является:

  • Код или класс, который открывает файл, отвечает за его закрытие.

  • Если вы передаете InputStream другому методу, который читает его, этот метод не должен закрывать его. Оставьте это для кода, который его открыл. Это как владелец потоков.

  • Аналогично, если вы передаете OutputStream другому методу, который пишет на него, этот метод не должен закрывать его. Оставьте это для кода, которому это принадлежит. НО, если вы переносите поток в другие классы, которые могут буферизовать некоторые данные, вызовите на них .flush(), чтобы убедиться, что все вышло!

  • Если вы пишете свои собственные классы-оболочки вокруг InputStream и OutputStream, не закрывайте поток делегатов в своем финализаторе. Если поток нужно очистить во время GC, он должен сам это обработать.

В вашем примере кода просто не закрывайте этот сканер. Вы не открывали стандартный ввод, поэтому вам не нужно его закрывать.

Ответ 3

Поскольку потоки неограничены. Вы просматриваете значения из потоков по мере необходимости. Затем, когда закончите, просто закройте его. Потоки не содержат все данные в памяти. Потоки предназначены для обработки относительно большого объема данных, которые не могут храниться в памяти. Таким образом, вы не можете повторно открыть поток просто потому, что вы уже сделали цикл над ним и исчерпали все данные. Поскольку поток не хранит эти данные в памяти. Они просто потеряны и почему вы не можете его снова открыть. Чем лучше вы создаете новый поток, чем снова открываете существующий.

Ответ 4

Стандартная библиотека Java выбрала "стандартизованный" подход к InputStream. Даже если вы можете законно воспринимать некоторые потоки, такие как данные, поступающие с входной консоли, как логически повторно открываемые, InputStream представляет общий подход, поскольку он предназначен для охвата всех возможных InputStream s, которые многие из они по своей природе не вновь открываются. Как прекрасно описано в ответе @JohnBollinger.