杰瑞科技汇

Python模块之binascii,如何使用它?

binascii 模块是 Python 中一个非常重要且常用的模块,它的名字来源于 "binary" 和 "ASCII",它的核心功能是在二进制数据(字节串)和各种 ASCII 编码的文本表示(如十六进制、Base64)之间进行转换。

Python模块之binascii,如何使用它?-图1
(图片来源网络,侵删)

当你需要处理二进制数据,但又想以文本形式(比如在日志中、URL里、或者配置文件里)存储或传输它时,binascii 就派上用场了。


为什么需要 binascii

想象一个场景:你有一个文件,比如一张图片 image.png是纯粹的二进制数据,包含了像素信息、颜色表等,如果你尝试直接读取这些二进制数据并将其打印出来,你会看到一堆乱码和不可见的控制字符,因为它们不是为人类阅读设计的。

为了解决这个问题,我们可以将这些二进制数据转换成一种文本格式,

  • 十六进制:每 4 位二进制转换成一个 0-9, a-f 的字符,非常直观。
  • Base64:一种使用 64 个常用字符来表示任意二进制数据的方法,广泛用于在文本协议(如 Email、JSON)中传输二进制附件。

binascii 模块就是专门用来高效地完成这些转换工作的。

Python模块之binascii,如何使用它?-图2
(图片来源网络,侵删)

核心功能与常用函数

binascii 模块提供了两组功能相似但接口不同的函数:

  1. a2b_ (ASCII to Binary) 和 b2a_ (Binary to ASCII) 开头的函数:它们处理的是字节串 (bytes) 和字节串 (bytes) 之间的转换,这是最常用、最推荐的方式。
  2. a2b_b2a_ 开头,但名称中包含 _hex_base64 的函数:它们处理的是字节串 (bytes) 和字符串 (str) 之间的转换,这些函数在 Python 2 中更常见,但在 Python 3 中也能使用,不过需要注意编码问题。

下面我们重点介绍第一组,也就是现代 Python 开发中推荐使用的函数。

十六进制 编码与解码

这是最常用的转换之一。

binascii.b2a_hex(data)

  • 功能:将二进制数据编码为十六进制表示。
  • 参数data (bytes) - 要编码的二进制数据。
  • 返回值bytes - 包含小写十六进制字符的字节串。
  • 别名hexlify

binascii.a2b_hex(hexstr)

  • 功能:将十六进制表示解码为二进制数据。
  • 参数hexstr (bytes) - 包含十六进制字符的字节串。
  • 别名unhexlify

示例:

import binascii
# 原始二进制数据
original_data = b"Hello, World!"
# 1. 编码为十六进制
hex_data = binascii.b2a_hex(original_data)
print(f"原始数据: {original_data}")
print(f"编码后的十六进制 (bytes): {hex_data}")
print(f"解码后的字符串: {hex_data.decode('ascii')}") # 假设我们知道它是ASCII
# 2. 从十六进制解码回二进制
decoded_data = binascii.a2b_hex(hex_data)
print(f"解码回的二进制数据: {decoded_data}")
print(f"解码后的数据与原始数据是否相同: {decoded_data == original_data}")
# 也可以使用别名
hex_data_alias = binascii.hexlify(original_data)
decoded_data_alias = binascii.unhexlify(hex_data_alias)
print(f"使用别名编码: {hex_data_alias}")
print(f"使用别名解码: {decoded_data_alias}")

输出:

原始数据: b'Hello, World!'
编码后的十六进制 (bytes): b'48656c6c6f2c20576f726c6421'
解码后的字符串: 48656c6c6f2c20576f726c6421
解码回的二进制数据: b'Hello, World!'
解码后的数据与原始数据是否相同: True
使用别名编码: b'48656c6c6f2c20576f726c6421'
使用别名解码: b'Hello, World!'

Base64 编码与解码

Base64 在网络传输中非常常见,例如在邮件附件、JWT 令牌、图片的 Data URI 中。

binascii.b2a_base64(data, *, newline=True)

  • 功能:将二进制数据编码为 Base64 格式。
  • 参数
    • data (bytes): 要编码的二进制数据。
    • newline (bool): 是否在输出末尾添加换行符 \n,默认为 True,这符合 RFC 标准。
  • 返回值bytes - 包含 Base64 编码数据的字节串,末尾可能有一个换行符。

binascii.a2b_base64(data)

  • 功能:将 Base64 编码的数据解码为二进制数据。
  • 参数data (bytes) - 包含 Base64 编码数据的字节串,可以包含换行符。
  • 返回值bytes - 解码后的原始二进制数据。

示例:

import binascii
# 原始二进制数据
original_data = b"Python's binascii module is powerful."
# 1. 编码为 Base64
b64_data = binascii.b2a_base64(original_data, newline=False) # 去掉末尾的换行符
print(f"原始数据: {original_data}")
print(f"编码后的 Base64 (bytes): {b64_data}")
# 2. 从 Base64 解码回二进制
decoded_data = binascii.a2b_base64(b64_data)
print(f"解码回的二进制数据: {decoded_data}")
print(f"解码后的数据与原始数据是否相同: {decoded_data == original_data}")
# 如果包含换行符,a2b_base64 也能正确处理
b64_data_with_newline = binascii.b2a_base64(original_data)
decoded_data_with_newline = binascii.a2b_base64(b64_data_with_newline)
print(f"带换行符的解码结果: {decoded_data_with_newline}")

输出:

原始数据: b"Python's binascii module is powerful."
编码后的 Base64 (bytes): b'UHl0aG9uJ3MgYmluc2Fzc2UgbW9kdWxlIGlzIHBvdXI/ZnJvbmcu'
解码回的二进制数据: b"Python's binascii module is powerful."
解码后的数据与原始数据是否相同: True
带换行符的解码结果: b"Python's binascii module is powerful."

CRC 校验

binascii 还可以用来计算循环冗余校验,这是一种常用的校验数据完整性的方法。

binascii.crc32(data)

  • 功能:计算数据的 CRC32 校验和。
  • 参数data (bytes) - 要计算校验和的二进制数据。
  • 返回值int - 一个 32 位的整数,表示校验和,这个值可能是一个负数,你可以使用 & 0xffffffff 将其转换为无符号整数。

示例:

import binascii
data = b"Hello, World!"
checksum = binascii.crc32(data)
print(f"数据: {data}")
print(f"CRC32 校验和 (有符号): {checksum}")
print(f"CRC32 校验和 (无符号): {checksum & 0xffffffff}")
# 修改数据中的一个字节,校验和会完全不同
data_modified = b"Hello, World?" # ! 变成了 ?
checksum_modified = binascii.crc32(data_modified)
print(f"修改后的数据: {data_modified}")
print(f"修改后的 CRC32 校验和: {checksum_modified & 0xffffffff}")

输出:

数据: b'Hello, World!'
CRC32 校验和 (有符号): -1826328476
CRC32 校验和 (无符号): 3089625236
修改后的数据: b'Hello, World?'
修改后的 CRC32 校验和: 2206341478

binasciibase64hashlib 等模块的关系

Python 的标准库中还有其他模块也提供类似功能,binascii 和它们的关系如下:

功能 binascii 模块 base64 模块 hashlib 模块
Base64 编码/解码 b2a_base64, a2b_base64 b64encode, b64decode 不提供
Hex 编码/解码 b2a_hex, a2b_hex b16encode, b16decode 不提供
CRC 校验 crc32, crc_hqx 不提供 不提供
哈希摘要 不提供 不提供 md5, sha1, sha256

  • binascii:核心是 二进制与文本编码的转换,它非常高效,因为它通常是用 C 实现的,它的 CRC 功能是独一无二的。
  • base64:专注于 Base64 的编码和解码,它的 API 更现代(直接返回 bytes),有时比 binascii 的对应函数更方便。
  • hashlib:专注于 哈希算法(MD5, SHA 等),用于生成数据的“指纹”或摘要,用于校验完整性和加密,而不是为了数据表示。

如何选择?

  • 如果只是简单的 Hex 或 Base64 转换binasciibase64 都可以。base64 的 API 可能更简洁一些。
  • 如果需要计算 CRC 校验和,必须使用 binascii
  • 如果需要计算 MD5, SHA 等哈希值,必须使用 hashlib

实战应用场景

简单的文件哈希校验

虽然 hashlib 更适合,但 binascii 可以用来展示校验和的原理。

import binascii
def calculate_file_crc(filepath):
    """计算文件的 CRC32 校验和"""
    with open(filepath, 'rb') as f:
        file_data = f.read()
    return binascii.crc32(file_data)
# 假设你有一个名为 'my_image.png' 的文件
# checksum = calculate_file_crc('my_image.png')
# print(f"File checksum: {checksum & 0xffffffff}")

在 JSON 中传输二进制数据

JSON 标准不支持二进制数据,一个常见的解决方案是先将二进制数据用 Base64 编码,然后以字符串的形式存入 JSON。

import binascii
import json
# 1. 原始二进制数据
binary_data = b"{'key': 'value', 'data': [1, 2, 3]}"
# 2. 使用 binascii 编码为 Base64
b64_encoded_data = binascii.b2a_base64(binary_data, newline=False).decode('ascii')
# 3. 构造 JSON 对象
payload = {
    "filename": "config.dat",
    "content_type": "application/octet-stream",
    "data": b64_encoded_data  # Base64 字符串
}
# 4. 序列化为 JSON 字符串
json_string = json.dumps(payload)
print("JSON to be sent:")
print(json_string)
# 5. 接收方解析 JSON 并解码
received_payload = json.loads(json_string)
received_b64_data = received_payload['data']
# 6. 使用 binascii 解码回二进制
decoded_binary_data = binascii.a2b_base64(received_b64_data.encode('ascii'))
print("\nDecoded binary data:")
print(decoded_binary_data)
print(f"Is original data equal? {decoded_binary_data == binary_data}")

注意事项

  1. Python 3 的 bytes vs str:在 Python 3 中,binascii 的核心函数都严格地在 bytes 类型上工作,不要尝试将 str (Unicode 字符串) 直接传给它们,除非你明确知道它的编码并已经用 .encode() 转换过了。
  2. 错误处理:如果传入的 hexstrb64_data 包含非法字符,a2b_hexa2b_base64 会抛出 binascii.Error 异常,建议使用 try...except 来捕获这个异常。
    try:
        bad_hex = binascii.a2b_hex(b'ghijkl') # g, h 不是合法的十六进制字符
    except binascii.Error as e:
        print(f"解码失败: {e}")

binascii 是 Python 中处理二进制数据与文本格式之间转换的基石,虽然 base64 等模块在某些方面提供了更现代的接口,但 binascii 凭借其高效性和独特的 CRC 功能,在 Python 开发工具箱中占据着不可或缺的地位,当你需要处理 Hex、Base64 编码或进行简单的数据校验时,binascii 应是你的首选之一。

分享:
扫描分享到社交APP
上一篇
下一篇