Записать строку из 1 и 0 в двоичный файл? - PullRequest
10 голосов
/ 03 сентября 2011

Я хочу взять строку из 1 и 0 и преобразовать ее в настоящий двоичный файл (просто запись строки из 1 и 0 в файл просто сделает это либо файлом ascii, содержащим "00110001" и "00110000" s).).Я бы предпочел сделать это на python или напрямую из оболочки bash, но java или C тоже подойдут.это вероятно одноразовое использование.

Спасибо.

Ответы [ 5 ]

17 голосов
/ 03 сентября 2011

В Python используйте встроенную функцию int для преобразования строки 0 и 1 в число:

>>> int("00100101", 2)
37

Затем используйте встроенный chr для преобразования 8-разрядного целого числа (то есть в включающем диапазоне 0-255) в символ.

>>> chr(_)
'%'

Результат chr может быть просто записан в файл (открытый в двоичном режиме) методом file.write.

6 голосов
/ 03 сентября 2011

Если у вас есть более 8 символов для преобразования (и я полагаю, что вы делаете), вам понадобится что-то вроде этого (с использованием Python):

>>> b = '0010101001010101010111101010100101011011'
>>> bytearray(int(b[x:x+8], 2) for x in range(0, len(b), 8))
bytearray(b'*U^\xa9[')

Это разбивает битовую строку на 8-символьные куски (и если ваша строка не кратна длине 8, вы должны сначала заполнить ее), преобразует каждый чанк в целое число, а затем преобразует список целых чисел в bytearray который может быть записан непосредственно в ваш двоичный файл (нет необходимости преобразовывать его в строку):

>>> with open('somefile', 'wb') as f:
...     f.write(the_bytearray)

Если у вас есть больше таких задач, то есть библиотеки, которые могут помочь, например, вот то же преобразование с использованием моего цепочки битов :

>>> from bitstring import BitArray
>>> with open('somefile', 'wb') as f:
...     BitArray(bin=b).tofile(f)
3 голосов
/ 03 сентября 2011

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

В этом случае двоичный код представляет собой простую степень 2, поэтому:

    1 << 1 = 1
    1 << 2 = 2
    1 << 3 = 4
    1 << 4 = 8

и так далее ...

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

    (1 << 7) + (0 << 6) + (1 << 5) + (0 << 4) + (0 << 3) + (1 << 2) + (0 << 1) + 1

Предполагая, что вы прошли и преобразовали каждое "0" или "1" в его числовой формат первым.

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

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

Если вы пометите столбцы сверху в двоичном виде, вы легко поймете, о чем я ... взяв приведенный выше пример (помните, что это все степени 2):

    1   0  1  0  0 1 0 1
    128 64 32 16 8 4 2 1 = 128 + 32 + 4 + 1 = 165

Не является частью вопроса, но связан ... и продвигается на один шаг вперед:

Шестнадцатеричное - это значения от 0 до F (16 значений), каждое из которых может вписаться в 4 бита ... так что

    1010 0101 (8+2) (4+1) - Binary using powers of 2 only on 4 bits (8 4 2 1)
    10   5    (Decimal) - (10 << 4) + 5 = 165
    A    5    (Hexadecimal)
1 голос
/ 03 сентября 2011

В java у вас есть встроенная функция Integer.parseInt (String strBinaryNumber, int radix).

Которые работают как ..

             String strBinaryNumber="00100101";
     System.out.println(Integer.parseInt(strBinaryNumber,2));

Вывод будет: 37

но Исключение типа NumberFormatException выдается, если возникает любая из следующих ситуаций:

  1. Первый аргумент равен нулю или представляет собой строку нулевой длины.
  2. Основание либо меньше, чем Character.MIN_RADIX, либо больше, чем Character.MAX_RADIX.
  3. Любой символ строки не является цифрой указанного радиуса, за исключением того, что первый символ может быть знаком минус '-' ('\ u002D') при условии, что длина строки превышает длину 1. 4. Значение, представленное строкой, не является значением типа int.
1 голос
/ 03 сентября 2011

Это не так уж и практично, но вот один из способов сделать это в сценарии оболочки.Примечание: он использует bc

#!/bin/bash

# Name of your output file
OFILE="output.txt"

# A goofy wrapper to convert a sequence of 8 1s and 0s into a 8-bit number, expressed in hex
function bstr_to_byte()
{
    echo "obase=16;ibase=2;$1" | bc
}


# Build input string from stdin
#   This can be done using pipes ( echo "1010101..." | ./binstr.sh
#   Or "interactively", so long as you enter q on it's own line when you are done entering your
#       binary string.
ISTR=""
while read data; do
    if [[ ${data} != "q" ]] ; then
        ISTR="${ISTR}${data}"
    else
        break
    fi
done

# Byte-by-byte conversion
while [[ $(expr length ${ISTR}) -ge 8 ]] ; do
    # Copy the first 8 characters
    BSTR=${ISTR:0:8}
    # Drop them from the input string
    ISTR=${ISTR:8}
    # Convert the byte-string into a byte
    BYTE=$(bstr_to_byte $BSTR)

    # Debug print
    ##echo "$BSTR => [ ${BYTE} ]"

    # Write character to file
    echo -en "\x${BYTE}" >> ${OFILE}

    # Check for empty ISTR, which will cause error on iteration
    if [[ -z ${ISTR} ]] ; then
        ##echo "String parsed evenly"
        break
    fi
done

##echo "Remaining, unparsed characters: ${ISTR}"

Который, если вы назовете binstr.sh, может быть запущен с помощью pdipd, например:

echo "11001100" | ./binstr.sh

Вы можете проверить это с помощью hexdumpНапример, hexdump output.txt

Я должен отметить, что это предполагает, что ваша строка сначала вводится с MSB.Он также просто отбрасывает любое количество «битов», которые не образуют полный байт.Вы можете изменить это или просто убедиться, что вы достаточно полно добавили свой ввод.

Наконец, есть несколько строк отладки, которые я оставил там, но закомментировал их двойными знаками #.

...