преобразовать текстовый файл битов в двоичный файл

преобразовать текстовый файл битов в двоичный файл

У меня есть файл instructions.txtс содержимым:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Как мне создать двоичный файл instructions.binс теми же данными, что и instructions.txt. Другими словами, .binфайл должен быть таким же 192 битами, как и в .txtфайле, с 32 битами на строку. Я использую bash на Ubuntu Linux. Я пытался использовать, xxd -b instructions.txtно вывод намного длиннее 192 бит.

решение1

oneliner для преобразования 32-битных строк из единиц и нулей в соответствующие двоичные данные:

$ perl -ne 'print pack("B32", $_)' < instructions.txt > instructions.bin

что оно делает:

  • perl -neбудет перебирать каждую строку входного файла, предоставленную на STDIN ( instructions.txt)
  • pack("B32", $_)возьмет список строк из 32 бит ( $_который мы только что считывали из STDIN) и преобразует его в двоичное значение (вы можете использовать его в качестве альтернативы, "b32"если вам нужен возрастающий порядок бит внутри каждого байта вместо убывания; см. perldoc -f packдля получения более подробной информации)
  • printзатем выведем это преобразованное значение в STDOUT, который затем перенаправим в наш двоичный файлinstructions.bin

проверять:

$ hexdump -Cv instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018

$ xxd -b -c4 instructions.bin
00000000: 00000000 00000000 00000000 00010011  ....
00000004: 00000010 11010001 00100000 10000011  .. .
00000008: 00000000 01110011 00000010 10110011  .s..
0000000c: 00000000 01110011 00000100 00110011  .s.3
00000010: 00000000 01110011 01100100 10110011  .sd.
00000014: 00000000 00000000 00000000 00010011  ....

решение2

Добавление -rопции (обратный режим) на xxd -bсамом деле не работает так, как задумано, потому что xxd просто не поддерживает объединение этих двух флагов (он игнорирует, -bесли указаны оба). Вместо этого вам придется сначала преобразовать биты в шестнадцатеричные самостоятельно. Например, так:

( echo 'obase=16;ibase=2'; sed -Ee 's/[01]{4}/;\0/g' instructions.txt ) | bc | xxd -r -p > instructions.bin

Полное объяснение:

  • Часть в скобках создает bcскрипт. Сначала он устанавливает входную базу в двоичную (2), а выходную базу в шестнадцатеричную (16). После этого команда sedвыводит содержимое instructions.txtс точкой с запятой между каждой группой из 4 бит, что соответствует 1 шестнадцатеричной цифре. Результат передается в bc.
  • Точка с запятой является разделителем команд в bc, поэтому все, что делает скрипт, — это выводит каждое входное целое число обратно (после преобразования основания).
  • Выходные данные bcпредставляют собой последовательность шестнадцатеричных цифр, которую можно преобразовать в файл с обычным расширением xxd -r -p.

Выход:

$ hexdump -Cv instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018
$ xxd -b -c4 instructions.bin
00000000: 00000000 00000000 00000000 00010011  ....
00000004: 00000010 11010001 00100000 10000011  .. .
00000008: 00000000 01110011 00000010 10110011  .s..
0000000c: 00000000 01110011 00000100 00110011  .s.3
00000010: 00000000 01110011 01100100 10110011  .sd.
00000014: 00000000 00000000 00000000 00010011  ....

решение3

Мойоригинальный ответбыл неверен - xxdне может принять ни то, ни -pдругое -rс -b...

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

Вход

$ cat instructions.txt
00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Выход

$ hexdump -Cv < instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018

Конвейер Bash:

cat instructions.txt \
    | tr -d $'\n' \
    | while read -N 4 nibble; do 
        printf '%x' "$((2#${nibble}))"; \
      done \
    | xxd -r -p \
    > instructions.bin
  • cat- необязательно, но используется для ясности
  • tr -d $'\n' - remove all newlines from the input
  • read -N 4 nibble- читатьточно4× символа в nibbleпеременную
  • printf '%x' "$((2#${nibble}))"преобразовать полубайт из двоичного в шестнадцатеричный символ 1×
    • $((2#...))- преобразовать заданное значение из двоичной системы счисления в десятичную систему счисления
    • printf '%x'- отформатировать заданное значение из десятичной системы счисления в шестнадцатеричную систему счисления
  • xxd -r -p- обратный ( -r) простой дамп ( -p) - из шестнадцатеричного в необработанный двоичный

Питон:

python << EOF > instructions.bin
d = '$(cat instructions.txt | tr -d $'\n')'
print(''.join([chr(int(d[i:i+8],2)) for i in range(0, len(d), 8)]))
EOF
  • Нецитируемыйхередок( << EOF) используется для помещения содержимого в код Python
    • Это неэффективно, если входные данные становятся большими.
  • catи tr- используется для получения чистого (однострочного) ввода
  • range(0, len(d), 8)- получить список чисел от 0 до конца строки d, шаг за шагом 8× символов.
  • chr(int(d[i:i+8],2))- преобразовать текущий срез ( d[i:i+8]) из двоичного в десятичный ( int(..., 2)), а затем в необработанный символ ( chr(...))
  • [ x for y in z]-понимание списка
  • ''.join(...)- преобразовать список символов в одну строку
  • print(...)- распечатать это

решение4

Двоичные файлы не разделяют строки символами новой строки. Двоичные файлы не имеют разделителей; это просто один файл с кучей 0 и 1, хранящийся на каком-то устройстве, организованном в секторах, контролируемых таблицей размещения файлов или аналогичным отображением, чтобы придать ему смысл.

Вы можете либо преобразовать текстовый файл в двоичный формат, получив в результате 192 бита (24 байта), либо добавить символ новой строки после каждой 32-битной последовательности, чтобы получить файл с 6 дополнительными байтами.

Код ниже даст вам 192-битный файл, как и требовалось:

for x in $(cat file.txt); 
do s=${x:0:32}; 
echo $(printf '%08X' "$((2#$s))"); 
done | xxd -r -p > file.bin

Альтернативой является чтение 8 бит за раз, если не нужен дополнительный код для заполнения (4-байтовые строки в текстовом файле).

Протестировано на Ubuntu 16.04.7

Связанный контент