Как я должен читать из буферизованного устройства чтения?

StackOverflow https://stackoverflow.com/questions/2500107

Вопрос

У меня есть следующий пример чтения из буферизованного устройства чтения:

while ((inputLine = input.readLine()) != null) {
   System.out.println("I got a message from a client: " + inputLine);
}

Код в цикле println будет выполняться всякий раз, когда что-то появляется в буферизованном считывателе (input в данном случае).В моем случае, если клиентскоеприложение записывает что-то в сокет, код в цикле (в серверном приложении) будет выполнен.

Но я не понимаю, как это работает. inputLine = input.readLine() ожидает, пока что-то не появится в буферизованном считывателе, и когда что-то появляется там, оно возвращает true и код в цикле выполняется.Но когда null может быть возвращен.

Есть еще один вопрос.Приведенный выше код был взят из метода, который throws Exception и я использую этот код в методе run потока.И когда я пытаюсь поставить throws Exception перед тем, как run компилятор жалуется:переопределенный метод не генерирует исключение.Без throws exception У меня есть еще одна жалоба от компилятора:незарегистрированное исключение.Итак, что я могу сделать?

Это было полезно?

Решение

Когда сокет на другом конце закрыт, считыватель должен вернуть нулевую строку.Это то условие, которое вы ищете.Чтобы обработать исключение, оберните цикл чтения в блок try / catch.

 try {
   while ((inputLine = input.readLine()) != null) {
     System.out.println("I got a message from a client: " + inputLine);
   }
 }
 catch (IOException e) {
   System.err.println("Error: " + e);
 }

Возможно, вы найдете это Учебник при чтении / записи из / в сокет на Java полезно.

Другие советы

На ваш первый вопрос:

Но я не понимаю, как это работает.inputLine = input.readLine() ожидает, пока что-то не появится в буферизованном считывателе, и когда что-то там появляется, оно возвращает true, и код в цикле выполняется.Но когда null может быть возвращен.

BufferedReader.readLine() не возвращается true после успеха.Он возвращает строку, содержащую строку, которая была прочитана.Если достигнут конец потока, он возвращает null.

Ваш второй вопрос:

Приведенный выше код был взят из метода, который генерирует исключение, и я использую этот код в методе run потока.И когда я пытаюсь поставить throws Exception перед запуском, компилятор жалуется:переопределенный метод не генерирует исключение.Без исключения throws у меня есть еще одна жалоба от компилятора:незарегистрированное исключение.Итак, что я могу сделать?

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

try {
    while ((inputLine = input.readLine()) != null) {
        System.out.println("I got a message from a client: " + inputLine);
    }
} catch (Exception e) {
    //handle exception
}

readLine() читателя вернет строковое значение, когда у него есть что-то прочитанное, пустую строку, когда еще ничего нет, и null, когда соединение закрыто.

Я бы рекомендовал обернуть try / catch вокруг вашего блока кода с помощью функции ввода-вывода и соответствующим образом обрабатывать ошибки.

input считыватель подключен к сокету, который является прослушивателем, т. е.продолжает прослушивать входящие сообщения.

Что касается вашего второго вопроса, вы должны поместить блок try / catch внутри метода, перехватить исключение и обработать его.Не выбрасывайте его повторно.

Но я не понимаю, как это работает.....ожидает, пока что-то не появится в буферизованном считывателе, и когда что-то появляется там, оно возвращает true

Нет, он возвращает значение выражения (inputLine = input.readLine()), саму входную строку.Входная строка сравнивается с null.

значение null возвращается при достижении значения "EOF (Конец файла)".Поскольку это чтение из сетевого сокета, конец файла создается при отключении сокета (либо сервером, либо клиентом), но вы, скорее всего, получите исключение до того, как действительно увидите EOF.

Если это не для домашней работы, возможно, вы захотите взглянуть на Apache Commons Учетные записи.

Предполагая, что вы не создаете BufferedReader, а просто останавливаетесь на InputStream:

String results = IOUtils.toString(inputStream);
System.out.println(results);
while ((inputLine = input.readLine()) != null) {

Посмотрите на каждую часть выражения:

input.readLine()

Возвращает строку, которая будет равна null, если достигнут конец потока (или генерирует исключение при ошибке).

inputLine = input.readLine()

Присваивает эту строку inputLine

((inputLine = input.readLine()) != null)

Проверяет, что строка, которая была назначена, не является null (конец потока).

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

Что касается результата от readLine(), он вернется null когда больше нечего читать.В случае сокета это происходит, когда другая сторона чисто закрывает сокет (любое внезапное завершение или нечистое закрытие обычно приводит к исключению в вашем коде, поскольку ОС отправляет уведомление о закрытии сокета другого типа).

У меня есть одно предостережение, поскольку вы оборачиваете сокет в java.io.BufferedReader.Вы должны быть очень осторожны, используя это в любом производственном коде.

Опасность заключается в том, что BufferedReader плохо справляется с исключениями в процессе чтения.Это особенно проблема, если вы включили тайм-аут в сокете, чтобы код автоматически получал периодические исключения из операционной системы.Тайм-аут (или другое исключение) может наступить во время заполнения буфера внутри устройства чтения.Если вы попытаетесь повторно использовать объект после исключения, он проигнорирует все предыдущее содержимое в буфере.Пакеты, которые были получены ранее, автоматически теряются, и нет способа восстановить эти байты.

Обратите внимание, что существуют другие виды исключений сокета, которые не означают, что сокет был потерян.Например, посмотрите на определение java.io.InterruptedIOException.У этого есть общедоступная переменная, которая сообщает о количестве байтов, успешно переданных в самом последнем запросе ввода-вывода (чтения или записи).Это означает, что операция ввода-вывода может быть выполнена снова для извлечения или отправки оставшихся байтов для пакета.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top