Проблема кодировки Base64 в Python - PullRequest
0 голосов
/ 10 сентября 2018

Мне нужно сохранить файл параметров в python, и этот файл параметров содержит некоторые параметры, которые я не оставлю в простом тексте, поэтому я кодифицирую весь файл в base64 (я знаю, что это не самая безопасная кодировка мир, но он работает для данных, которые мне нужно использовать).

С кодировкой все работает хорошо. Я кодирую содержимое моего файла (просто текст с правильным расширением) и сохраняю файл. Проблема приходит с декодированием. Я печатаю текст, закодированный перед сохранением файла, и текст, закодированный из сохраненного файла, и они точно такие же, но по причине, которую я не знаю, декодирование текста сохраненного файла возвращает мне эту ошибку UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8d in position 1: invalid start byte и декодирование текста перед сохранением файла работает хорошо.

Любая идея, чтобы решить эту проблему?

Это мой код, я пытался преобразовать все в байты, в строку и все ...

params = open('params.bpr','r').read()


paramsencoded = base64.b64encode(bytes(params,'utf-8'))

print(paramsencoded)

paramsdecoded = str(base64.b64decode(str(paramsencoded,'utf-8')),'utf-8')

newparams = open('paramsencoded.bpr','w+',encoding='utf-8')
newparams.write(str(paramsencoded))
newparams.close()

params2 = open('paramsencoded.bpr',encoding='utf-8').read()
print(params2)

paramsdecoded = str(base64.b64decode(str(paramsencoded,'utf-8')),'utf-8')

paramsdecoded = base64.b64decode(str(params2))

print(str(paramsdecoded,'utf-8'))

1 Ответ

0 голосов
/ 10 сентября 2018

Ваша ошибка заключается в обработке объекта bytes, возвращаемого base64.b64encode(), вы вызвали str() для объекта:

newparams.write(str(paramsencoded))

То, что не декодирует объект bytes:

>>> bytesvalue = b'abc='
>>> str(bytesvalue)
"b'abc='"

Обратите внимание на обозначение b'...'. Вы создали представление объекта bytes, который представляет собой строку, содержащую синтаксис Python, которая может воспроизводить значение для целей отладки (вы можете скопировать это строковое значение и вставить его в Python, чтобы заново создать тот же bytes значение).

Поначалу это может быть не так легко заметить, поскольку base64.b64encode() в противном случае выдает только выходные данные с печатаемыми байтами ASCII.

Но ваша проблема с декодированием возникает из-за того, что при декодировании значение, считываемое из файла, включает в себя символы b' в начале. Эти первые два символа интерпретируются как данные Base64 тоже ; b является допустимым символом Base64, а ' игнорируется анализатором:

>>> bytesvalue = b'hello world'
>>> base64.b64encode(bytesvalue)
b'aGVsbG8gd29ybGQ='
>>> str(base64.b64encode(bytesvalue))
"b'aGVsbG8gd29ybGQ='"
>>> base64.b64decode(str(base64.b64encode(bytesvalue)))  # with str()
b'm\xa1\x95\xb1\xb1\xbc\x81\xdd\xbd\xc9\xb1\x90'
>>> base64.b64decode(base64.b64encode(bytesvalue))       # without str()
b'hello world'

Обратите внимание, что вывод совершенно отличается , потому что декодирование Base64 теперь начинается с неправильного места, так как b - это первые 6 бит первого байта (что делает первый декодированный байт 6C , 6D, 6E или 6F байтов, поэтому m, n, o или p ASCII).

Вы могли бы правильно декодировать значение (используя paramsencoded.decode('ascii') или str(paramsencoded, 'ascii')), но вы не должны обрабатывать эти данные как текст.

Вместо этого откройте файлы в двоичном режиме . Затем чтение и запись работают с bytes объектами, а функции base64.b64encode() и base64.b64decode() также работают с bytes, обеспечивая идеальное совпадение:

with open('params.bpr', 'rb') as params_source:
    params = params_source.read()  # bytes object

params_encoded = base64.b64encode(params)
print(params_encoded.decode('ascii'))   # base64 data is always ASCII data

params_decoded = base64.b64decode(params_encoded)

with open('paramsencoded.bpr', 'wb') as new_params:
    newparams.write(params_encoded)  # write binary data

with open('paramsencoded.bpr', 'rb') as new_params:
    params_written = new_params.read()

print(params_written.decode('ascii'))  # still Base64 data, so decode as ASCII

params_decoded = base64.b64decode(params_written)  # decode the bytes value

print(params_decoded.decode('utf8'))  # assuming the original source was UTF-8

Я явно использую bytes.decode(codec) вместо str(..., codec), чтобы избежать случайных str(...) вызовов.

...