Ваша ошибка заключается в обработке объекта 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(...)
вызовов.