将字节字符串转换为Base64编码字符串(输出不是字节字符串)

20
我想知道是否有可能将我从文件中读取的字节字符串转换为字符串(因此type(output) == str)。到目前为止,我在Google上找到的所有答案都像如何对PNG图像进行Base64编码以在CSS文件中使用数据URI? ,这似乎可以在Python 2中运行(在那里,如果我没有弄错,字符串本来就是字节字符串),但在Python 3.4中不再起作用。我想将这个结果字节字符串转换为普通字符串的原因是我想使用这个base64编码的数据存储在JSON对象中,但我一直收到类似以下错误的错误消息:
TypeError: b'Zm9v' is not JSON serializable

这里是一个最简单的出错示例:

import base64
import json
data = b'foo'
myObj = [base64.b64encode(data)]
json_str = json.dumps(myObj)
所以我的问题是:是否有一种方法可以将这个bytes类型的对象转换为str类型的对象,同时仍保留base64编码(所以在这个例子中,我希望结果是["Zm9v"]。这可行吗?
4个回答

14

对我有效的方法是将b64encode这一行更改为:

myObj = [base64.b64encode(data).decode('ascii')]
这在https://dev59.com/4VgQ5IYBdhLWcg3wcTaH#42776711中有解释:

base64被有意地归类为二进制转换...这是Python 3中的一个设计决策,强制将字节和文本分离并禁止隐式转换。

对我来说(Python 3.9),被接受的答案不起作用,会出现以下错误:

Traceback (most recent call last):
  File "/tmp/x.py", line 4, in <module>
    myObj = [base64.b64encode(data)]
  File "/usr/lib64/python3.9/base64.py", line 58, in b64encode
    encoded = binascii.b2a_base64(s, newline=False)
TypeError: a bytes-like object is required, not 'str'

1
我刚刚在Python 3.6中尝试了被接受的答案,它似乎仍然有效。你有什么想法为什么这两个小版本之间会有破坏性的变化?小版本更新不应该有破坏性的变化,所以我很好奇。你能否也在Python 3.6中测试被接受的答案,看看是否能够在那里重现错误? - Joeytje50
Python 3.6 对我也不起作用:$ docker run --rm -it python:3.6 Python 3.6.12 (default, Nov 18 2020, 14:46:32) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import base64 >>> import json >>> data = b'foo'.decode('UTF-8') >>> myObj = [base64.b64encode(data)] Traceback (most recent call last): File "", line 1, in File "/usr/local/lib/python3.6/base64.py", line 58, in b64encode encoded = binascii.b2a_base64(s, newline=False) TypeError: a bytes-like object is required, not 'str' - jmou
抱歉格式不佳!这只是我在 Python 3.6 Docker 容器中运行命令的结果。 - jmou

13
尝试
data = b'foo'.decode('UTF-8')

代替

data = b'foo'

将其转换为字符串。


5

试试这个:

def bytes_to_base64_string(value: bytes) -> str:
   import base64
   return base64.b64encode(value).decode('ASCII')

有一个常见的误解,尤其是来自Java世界的人经常犯错。 bytes.decode('ASCII') 实际上是将字节编码为字符串,而不是解码它们。


不错的补充。虽然我会争辩说,至少在ASCII的情况下,它是一种直接映射,没有进行任何解码/解析。 - Victor - Reinstate Monica

2

我找不到一个可靠的答案来将字节转换为url安全的base64编码字符串,因此在这里发布我的解决方案。

假设你有一个输入:

mystring = b'\xab\x8c\xd3\x1fw\xbb\xaaz\xef\x0e\xcb|\xf0\xc3\xdfx=\x16\xeew7\xffU\ri/#\xcf0\x8a2\xa0'

将内容编码为base64

from base64 import b64encode # or urlsafe_b64decode
b64_mystring = b64encode(mystring) 

这将得到:b'q4zTH3e7qnrvDst88MPfeD0W7nc3/1UNaS8jzzCKMqA=',但仍需要解码,因为字节不可JSON序列化。
import requests
requests.get("https://google.com", json={"this": b64_mystring})

# raises "TypeError: Object of type bytes is not JSON serializable"

因此,我们使用:
from base64 import b64encode
b64_mystring = b64encode(mystring).decode("utf-8")

这给我们带来了:q4zTH3e7qnrvDst88MPfeD0W7nc3/1UNaS8jzzCKMqA=,现在可以使用json.dumps进行JSON序列化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接