Страницы

Поиск по вопросам

воскресенье, 29 марта 2020 г.

Преобразование из String в массив байтов и обратно

#java #кодировка #потоки_данных


Написал на Java следующую последовательность действий:


Получаю из строки с кириллицей массив байтов

byte[] bytes="новая строка".getBytes();

Получается следующий массив: 

[-19, -18, -30, -32, -1, 32, -15, -14, -16, -18, -22, -32]
Передаю его на вход классу ByteArrayOutputStream

ByteArrayOutputStream baos=new ByteArrayOutputStream();
baos.write(bytes);

Выполняю обратное преобразование из массива байтов в строку

System.out.println(baos.toString());

Программа выводит в консоль текст новая строка


Вопрос: так как кириллица в юникоде имеет кодепойнты, превышающие 1 тысячу (кодепойнт
буквы А, к примеру, равен 1040), а байт в Java может принимать значения от -128 до
127, следовательно при попытке преобразовать строку в массив типа byte должна происходить
потеря информации, как следствие - при вызове метода toString() строка должна восстановиться
некорректно. Но этого не произошло. В чем тут причина?
    


Ответы

Ответ 1



Это не юникод. String.getBytes() использует кодировку по-умолчанию платформы: Encodes this String into a sequence of bytes using the platform's default charset, storing the result into a new byte array. Кодировка по-умолчанию задается настройками Java, ее можно проверить с помощью: System.getProperty("file.encoding"); Для получения байтов в юникоде, задайте кодировку явно: byte[] bytes="новая строка".getBytes("UTF-8"); Получится больше 12 байтов. Обновление по вопросам в комментарии: Разве UTF-8 выдает байты, эквивалентные юникодовскому представлению? У юникода бывают разные представления. UTF-8 — одно из них. Я знаю, что char выдает кодепойнты юникода. Если вывести System.out.println((byte)'н'), то это будет равно 61. Здесь можно посмотреть как строчная кириллическая «н» представляется в разных кодировках: https://unicode-table.com/en/043D/ UTF-8: Десятичное значение: 53437 Байты: 208 189 UTF-16BE: Десятичное значение: 1085 Байты: 4 61 Для char в Java, согласно спецификации (§3.1 Unicode) используется кодировка UTF-16. Это тоже двухбайтовая кодировка. Соответственно, когда Вы приводите char к byte Вы получаете младший байт в этой кодировке. Получить байты в "UTF-16BE" можно так: byte[] bytes="новая строка".getBytes("UTF-16BE"); Если вывести байты, как Вы предложили byte[] bytes="новая строка".getBytes("UTF-8"), то там первый байт равен -48, а не 61. Кодировка UTF-8, как указано ранее беззнаковые (от 0 до 255) байты: 208 и 189. Знаковые байты, соответственно, -48 и -67.

Комментариев нет:

Отправить комментарий