Как я могу решить эту проблему чтения потока?

Я пытаюсь прочитать ответ с URL-адреса, отправляющего тело JSON. Но мой код не может прочитать полный ответ. В моем коде есть проблема, но я этого не понимаю.

val url: URL = new URL("https://jsonplaceholder.typicode.com/todos/1")
val httpsConnection: HttpsURLConnection = url.openConnection().asInstanceOf[HttpsURLConnection]
httpsConnection.setRequestMethod("GET")
httpsConnection.setRequestProperty("Accept", "application/json")
httpsConnection.setRequestProperty("Accept-Language", "en_US")
val streamReader: InputStreamReader = new InputStreamReader(httpsConnection.getInputStream)
val bufferedReader = new BufferedReader(streamReader)
val stringBuffer: StringBuffer =new StringBuffer()
while(bufferedReader.readLine() != null){
  stringBuffer.append(bufferedReader.readLine())
}

println(stringBuffer.toString)

Этот приведенный выше код не дает мне фактического результата. Но если я избегаю обычного стиля Java и использую исходный код scala:

Source.fromInputStream(httpsConnection.getInputStream,"UTF8").getLines().foreach(println)

это дает фактический JSON.

В чем проблема в моем первом разделе кодов?

вы не теряете данные, потому что читаете строки в цикле while и ничего с ними не делаете?

niekname 28.05.2019 15:30

@niekname, я теряю данные в цикле while, если я проверяю строку с нулевым значением, я теряю данные, если также проверяю bufferedReader.read() != -1.

John 28.05.2019 15:34

Каково содержание данных, которые вы ожидаете получить? Вот что я получаю, когда запускаю ваш код: ""userId": 1, "title": "delectus aut autem",}"

Matthew 28.05.2019 15:38

Цикл while тратит впустую чтение строки. Может быть, сделать что-то вроде while (true) { String line = bufferedReader.readLineI(); если (строка == ноль) перерыв; строкаBuffer.append (строка); }

Jayr 28.05.2019 15:45

@Matthew Я ожидаю { "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}

John 28.05.2019 16:07

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

Matthew 28.05.2019 16:19
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
6
118
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

Следующий код извлекает ваш файл JSON по предоставленной вами ссылке, используя методы, предоставленные JSON.простой и Apache Commons IO:

public void getJson() throws IOException {

    java.net.URL url = new java.net.URL("https://jsonplaceholder.typicode.com/todos/1");
    String json = IOUtils.toString(url, Charset.forName("UTF-8"));
    System.out.println(json);
}
Ответ принят как подходящий

В этом месте:

while(bufferedReader.readLine() != null){
  stringBuffer.append(bufferedReader.readLine())
}

сначала вы вызываете readLine дважды, чтобы проверить, не является ли оно нулевым, а затем добавить к stringBuffer. Но на самом деле второй вызов получает другую линию, так что вы теряете каждую вторую строку.

Обычный способ чтения буферизованного потока в Java:

String line;

while ((line = r.readLine()) != null) {
   // do your stuff...
}

но присваивания в Scala возвращают Unit, так что это не сработает.

Так что, может быть, стоит использовать Stream.continually?

Stream
    .continually(bufferedReader.readLine())
    .takeWhile(_ != null)
    .foreach(stringBuffer.append)

readLine вызывается дважды, и InputStreamReader должен использовать кодировку источника. Здесь я взял ISO-8859-1, так как он не выдаст ошибку, как UTF-8. Также readLine отбрасывает окончание строки, а StringBuilder работает быстрее.

val streamReader: InputStreamReader = new InputStreamReader(httpsConnection.getInputStream,
    "ISO-8859-1")
val bufferedReader = new BufferedReader(streamReader)
val stringBuilder: StringBuilder = new StringBuilder()
while (true) {
  val line = bufferedReader.readLine();
  if (line == null) {
      break;
  }
  stringBuilder.append(line).append("\r\n");
}

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