Преобразование строкового представления битов в байт

Я только начинаю узнавать о сжатии файлов и столкнулся с трудностями. У меня есть приложение, которое будет кодировать строку, такую ​​как «программа», как сжатое двоичное представление "010100111111011000" (обратите внимание, что это все еще сохраняется как строка).

Encoding
g       111
r       10
a       110
p       010
o       011
m       00

Теперь мне нужно записать это в файловую систему с помощью FileOutputStream, у меня проблема в том, как преобразовать строку «010100111111011000» в _4 _ / _ 5_s для записи в файловую систему с помощью FileOutputStream?

Я никогда раньше не работал с битами / байтами, так что я здесь как бы в тупике.


person John Lotacs    schedule 26.11.2011    source источник
comment
Вы говорите о сжатом двоичном представлении, а затем говорите, что у вас есть String длиной 18 символов (010100111111011000) для представления слова длиной 7 символов (программа). Вы уверены, что имеете в виду то, что спрашиваете? Обычно эти биты устанавливаются в X байтах (в данном случае 3).   -  person Brian Roach    schedule 26.11.2011
comment
Найдите «операторы битового сдвига»: >>, >>>, <<.   -  person Kevin    schedule 26.11.2011
comment
Брайан, исходное сообщение имеет размер 56 бит при переводе в двоичный код, кодированное сообщение составляет всего 18 бит. Кевин, люди продолжают мне это говорить, но я все еще не могу провести связь между использованием этих операторов и возможностью преобразовать это в массив байтов.   -  person John Lotacs    schedule 26.11.2011
comment
@JohnLotacs - Нет, это не так, если вы говорите о Strings, о которых вы говорите в своем вопросе, что является источником путаницы. Если у вас есть String, как вы говорите, у вас нет битов. У вас есть набор символов 0 и 1 (в частности, у вас есть 16-битный символ Unicode для каждого, что заставляет вашу память использовать 36 байтов до накладных расходов объекта String) - чтобы было ясно, если у вас есть String, у вас есть текстовый представление набора битов, выраженное с помощью символов 0 и 1.   -  person Brian Roach    schedule 26.11.2011
comment
Брайан, вот в чем вопрос, преобразование строкового представления битов в набор байтов.   -  person John Lotacs    schedule 26.11.2011
comment
@JohnLotacs - вы бы никогда не отказались от того, о чем говорите. Зачем тебе String?   -  person Brian Roach    schedule 26.11.2011
comment
Потому что проще всего было построить эту карту кодирования с помощью дерева Хаффмана, выполняя обходы и добавляя 0/1 к префиксу StringBuffer. en.wikipedia.org/wiki/Huffman_coding   -  person John Lotacs    schedule 26.11.2011
comment
@JohnLotacs У вас есть окончательные решения где-то в коде? У меня точно такая же проблема, но я не могу заставить ее работать   -  person Jim Vercoelen    schedule 26.09.2016


Ответы (3)


Введение в операторы битового сдвига:

Во-первых, у нас есть оператор сдвига влево x << n. Это сдвинет все биты в x влево на n бит, заполняя новые биты нулями:

      1111 1111 
<< 3: 1111 1000

Затем у нас есть знаковый оператор сдвига вправо, x >> n. Это сдвигает все биты в x вправо на n, копируя знаковый бит в новые биты:

      1111 1111 
>> 3: 1111 1111

      1000 0000
>> 3: 1111 0000

      0111 1111 
>> 3: 0000 1111

Наконец, у нас есть оператор сдвига вправо с заполнением нулями, x >>> n. Это сдвигает все биты в x вправо на n бит, заполняя новые биты нулями:

       1111 1111 
>>> 3: 0001 1111

Вы также можете найти полезным оператор побитового ИЛИ x | y. Это сравнивает биты в каждой позиции в x и y, устанавливая бит нового числа включенным, если он был включен в x или y, в противном случае выключен:

  1010 0101
| 1010 1010
  ---------
  1010 1111

Вам могут понадобиться только предыдущие операторы для решения данной проблемы, но для полноты, вот два последних:

Поразрядный оператор и x & y устанавливает биты на выходе в единицу тогда и только тогда, когда бит включен как в x, так и в y:

  1010 0101
& 1010 1010
  ---------
  1010 0000

Оператор побитового xor x ^ y устанавливает выходные биты в единицу, если бит включен в одном или другом числе, но не в обоих:

  1010 0101
^ 1010 1010
  ---------
  0000 1111

Теперь применим их к текущей ситуации:

Вам нужно будет использовать операторы битового сдвига для добавления битов и управления ими. Начните устанавливать биты с правой стороны в соответствии с их строковыми представлениями и сдвиньте их. Продолжайте, пока не дойдете до конца байта, а затем перейдите к следующему байту. Допустим, мы хотим создать байтовое представление «1100 1010»:

Our byte    Target
---------   --------
0000 0000
            1100 1010
0000 0001   ^
            1100 1010
0000 0011    ^
            1100 1010
0000 0110     ^
            1100 1010
0000 1100      ^
            1100 1010
0001 1001        ^
            1100 1010
0011 0010         ^
            1100 1010
0110 0101          ^
            1100 1010
1100 1010           ^

Я, конечно же, предоставлю вам возможность применить это к своей работе.

person Kevin    schedule 26.11.2011
comment
Один вопрос, чтобы начать мой байт как 0000 0001, это то же самое, что и запись байта b = 1; ? Я не уверен, из-за знаковой природы байта, как узнать, что такое двоичное представление, потому что я не знаю, какой бит представляет знак. - person John Lotacs; 26.11.2011
comment
Вы можете это сделать, но для единообразия вам нужно начать с нулевого байта, а затем ввести цикл for или while. Я немного отредактирую пример, чтобы посмотреть, смогу ли я сделать его более понятным. - person Kevin; 26.11.2011

Разрежьте свой String на отрезки по 8 и вызовите Byte # parseByte. Если вы установите radix на 2, он будет анализировать String как двоичное число.

person Jeffrey    schedule 26.11.2011
comment
Исключение в основном потоке java.lang.NumberFormatException: значение вне допустимого диапазона. Значение: 10000000 Основание: 2 Он работает только с длиной 7, если нет ведущих нулей, какая-нибудь идея? - person John Lotacs; 26.11.2011
comment
@John Lotacs Я понятия не имею, зачем он это делает, но вы можете использовать Integer#parseInt и преобразовать его в byte для обходной путь. - person Jeffrey; 26.11.2011
comment
@jeff Это происходит потому, что byte подписан, поэтому он должен быть от -111 1111 до +111 1111 (от -128 до +127). Байт с битами 1000 0000 на самом деле равен -128, и его нужно передать синтаксическому анализатору как -1000 0000. - person Kevin; 26.11.2011
comment
@Kevin Почему нельзя просто взять 1000 000? Это просто небольшая лень со стороны кодера или я что-то упускаю? - person Jeffrey; 26.11.2011
comment
Метод parseByte анализирует значение текста, а не отдельные биты. 1000 0000 равно 128, что выходит за рамки для byte, максимальное значение которого равно 127. Оно находится в пределах диапазона для unsigned byte, но Java не имеет беззнаковых типов (кроме, я полагаю, char). - person Kevin; 26.11.2011
comment
@ Кевин Аааа, теперь я понимаю. Да, char без знака. - person Jeffrey; 26.11.2011

Я думаю, вы хотите записать эти нули и единицы как двоичные значения в файл. Итак, вы можете перебирать строку, принимая каждый раз 8 знаков (String.substring () или smth), и создавать байты с помощью конструктора Byte (String). На данный момент это самое простое решение, которое приходит мне в голову.

Если я не прав насчет проблемы, расскажите, пожалуйста, подробнее.

person Jakub Matczak    schedule 26.11.2011
comment
Я пробовал это, конструктор Byte (String) возьмет строку 0011 и буквально интерпретирует ее как десятичное число 11. - person John Lotacs; 26.11.2011
comment
Вот почему вам следует использовать конструктор Byte (String s, int radix) для установки двоичного основания. - person Jakub Matczak; 26.11.2011