InputStream такой же, как InputStreamReader, когда символ имеет 8 бит? - PullRequest
0 голосов
/ 12 мая 2018

Я читал о InputStream и InputStreamReader.Большинство людей сказали, что InputStream для байтов, а InputStreamReader для текста.

Поэтому я создал простой файл с одним символом, который был «a».Когда я использовал InputStream, чтобы прочитать файл и преобразовать его в char, он напечатал букву «а».И когда я сделал то же самое, но на этот раз с InputStreamReader, это также дало мне тот же результат.

Так в чем же разница?Я думал, что InputStream не сможет дать букву «а».

Означает ли это, что когда символ имеет 8 битов, разницы между InputStream и InputStreamReader не будет?Правда ли, что между персонажами будет больше, чем один byte?

.

1 Ответ

0 голосов
/ 13 мая 2018

Нет, InputStream и InputStreamReader не одинаковы даже для 8-битных символов.

Посмотрите на метод InputStream read() без параметра. Возвращает int, но согласно документации возвращается байт (от 0 до 255) или -1 для EOF. Другие методы чтения работают с массивами байтов.

InputStreamReader наследуется от Reader. Метод * read () 1015 * без параметра также возвращает int. Но здесь значение int (в диапазоне от 0 до 65535) интерпретируется как символ или -1 для EOF. Другие методы чтения работают с массивами char напрямую.

Разница заключается в кодировке. Для конструкторов InputStreamReader требуется явная кодировка или используется кодировка платформы по умолчанию. Кодировка - это перевод между байтами и символами.

Вы сказали: "Когда я использовал InputStream, чтобы прочитать файл и преобразовать его в символ, он напечатал букву 'a'." Итак, вы прочитали байт и преобразовали его в символ вручную. Эта часть преобразования встроена в InputStreamReader с использованием кодировки для перевода.

Даже для однобайтовых наборов символов существуют различия. Итак, вашим примером является буква «а», которая имеет шестнадцатеричное значение 61 для кодировки Windows ANSI (названной «Cp1252» в Java). Но для кодировки IBM-Thai байт 0x61 интерпретируется как "/".

Так что люди сказали правильно. InputStream для двоичных данных и, кроме того, InputStreamReader для текста, переводя двоичные данные в текст в соответствии с кодировкой.

Вот простой пример:

import java.io.*;

public class EncodingExample {

  public static void main(String[] args) throws Exception {
    // Prepare the byte buffer for character 'a' in Windows-ANSI
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    final PrintWriter writer = new PrintWriter(new OutputStreamWriter(baos, "Cp1252"));
    writer.print('a');
    writer.flush();
    final byte[] buffer = baos.toByteArray();

    readAsBytes(new ByteArrayInputStream(buffer));
    readWithEncoding(new ByteArrayInputStream(buffer), "Cp1252");
    readWithEncoding(new ByteArrayInputStream(buffer), "IBM-Thai");
  }

  /**
   * Reads and displays the InputStream's bytes as hexadecimal.
   * @param in The inputStream
   * @throws Exception
   */
  private static void readAsBytes(InputStream in) throws Exception {
    int c;
    while((c = in.read()) != -1) {
      final byte b = (byte) c;
      System.out.println(String.format("Hex: %x ", b));
    }
  }

  /**
   * Reads the InputStream with an InputStreamReader and the given encoding.
   * Prints the resulting text to the console.
   * @param in The input stream
   * @param encoding The encoding
   * @throws Exception
   */
  private static void readWithEncoding(InputStream in, String encoding) throws Exception {
    Reader reader = new InputStreamReader(in, encoding);
    int c;
    final StringBuilder sb = new StringBuilder();
    while((c = reader.read()) != -1) {
      sb.append((char) c);
    }
    System.out.println(String.format("Interpreted with encoding '%s': %s", encoding, sb.toString()));
  }
}

Вывод:

Hex: 61 
Interpreted with encoding 'Cp1252': a
Interpreted with encoding 'IBM-Thai': /
...