我需要在python中保存一个params文件,这个params文件包含一些我不会留在纯文本上的参数,所以我将整个文件编码为base64(我知道这不是世界上最安全的编码但是它适用于我需要使用的那种数据)。
通过编码,一切运行良好。我编码我的文件的内容(一个简单的txt与适当的扩展名)并保存文件。问题来自解码。我打印保存文件之前编码的文本和保存文件编码的文本完全一样,但由于一个我不知道的原因,保存文件的文本解码返回我的错误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'))
你的错误在于你处理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(...)
电话。