查看: 3357|回复: 3

Python bytes与bytearray二进制处理与编码解

[复制链接]
发表于 2026-9-20 10:00:00 | 显示全部楼层 |阅读模式
在 Python 3 中,str 是处理文本的主力,但网络数据包、图片文件、二进制协议、加密解密等场景,必须使用 bytes 或 bytearray。核心关系是:str 是 Unicode 字符序列,bytes 和 bytearray 是 0-255 的整数序列,两者通过 encode() 和 decode() 相互转换。

一、字符、编码与字节

计算机只能存储 bit,8 个 bit 组成一个 byte,一个字节可表示 0-255。字符要存储和传输,必须先编码成字节序列。同一个字符在不同编码下字节数不同,例如“中”在 UTF-8 下占 3 字节,在 GBK 下占 2 字节,在 ASCII 下无法编码。
  1. char = '中'
  2. print(len(char.encode('utf-8')))
  3. print(len(char.encode('gbk')))
复制代码

str 的元素是长度为 1 的 str,bytes 的元素是 int。下面代码中 len(text) 是字符数 8,len(data) 是字节数 12,data[0] 是 80,而不是字符 'P'。
  1. text = 'Python编程'
  2. data = text.encode('utf-8')
  3. print(type(text), len(text), text[0])
  4. print(type(data), len(data), data[0])
复制代码

二、bytes 创建与操作

bytes 是不可变字节序列。常见创建方式包括 b 前缀字面量、bytes() 整数序列、指定长度生成全零字节,以及从 str 调用 encode()。
  1. data1 = b'hello'
  2. data2 = bytes([72, 101, 108, 108, 111])
  3. data3 = bytes(10)
  4. data4 = 'Python编程'.encode('utf-8')
  5. print(data1)
  6. print(data2)
  7. print(len(data3))
  8. print(data4)
复制代码

bytes 索引访问返回整数,切片返回 bytes;成员检查可以用整数,也可以用单字节 bytes。常用方法包括 find、rfind、index、count、startswith、endswith、split、partition、replace、strip、isalpha、isdigit、join 等。
  1. data = b'hello world hello python'
  2. print(data[0])
  3. print(data[:5])
  4. print(data.find(b'hello'))
  5. print(data.rfind(b'hello'))
  6. print(data.count(b'hello'))
  7. print(data.split())
  8. print(data.replace(b'hello', b'hi', 1))
  9. print(b' '.join([b'hello', b'world']))
复制代码

因为 bytes 不可变,不能执行 data[0] = 106,否则会抛 TypeError。

三、bytearray 可变字节序列

bytearray 是 bytes 的可变版本,支持原地修改,适合网络缓冲区累积、图像数据处理等频繁修改字节的场景。它的元素仍然是 0-255 整数。
  1. ba = bytearray(b'hello world')
  2. ba[0] = ord('H')
  3. print(ba)
  4. ba[6:11] = b'python'
  5. print(ba)
  6. ba.append(33)
  7. ba.extend(b' world')
  8. ba.insert(5, ord(','))
  9. print(ba)
  10. last = ba.pop()
  11. print(last)
  12. ba.reverse()
  13. print(ba)
复制代码

bytearray 提供类似 list 的 append、extend、insert、pop、remove、reverse、clear,也有 copy() 方法。bytes(ba) 可以得到不可变拷贝。查找、替换、大小写等方法和 bytes 类似。

四、encode/decode 与错误处理

encode 从 str 到 bytes,decode 从 bytes 到 str。用错编码会乱码或抛 UnicodeDecodeError。errors 参数控制异常字符处理:strict 默认抛异常;ignore 忽略;replace 替换为 ? 或 U+FFFD;xmlcharrefreplace、backslashreplace、namereplace 用于 ASCII 编码时替换不可编码字符。
  1. text = 'Python编程'
  2. utf8_data = text.encode('utf-8')
  3. print(utf8_data.decode('utf-8'))
  4. gbk_data = text.encode('gbk')
  5. print(gbk_data.decode('gbk'))
  6. bad = b'hello' + bytes([255]) + b'world'
  7. print(bad.decode('utf-8', errors='ignore'))
  8. print(bad.decode('utf-8', errors='replace'))
复制代码

处理未知编码时,可以按常见编码依次尝试解码。下面函数尝试 utf-8、gbk、gb2312、iso-8859-1、windows-1252,并用替换字符比例做简单判断。
  1. def safe_decode(data):
  2.     encodings = ['utf-8', 'gbk', 'gb2312', 'iso-8859-1', 'windows-1252']
  3.     for enc in encodings:
  4.         try:
  5.             decoded = data.decode(enc)
  6.             if decoded.count('�') / max(len(decoded), 1) < 0.1:
  7.                 return enc, decoded
  8.         except (UnicodeDecodeError, UnicodeError):
  9.             continue
  10.     return 'utf-8', data.decode('utf-8', errors='replace')
复制代码

BOM 是字节顺序标记。UTF-8 BOM 为 EF BB BF,utf-8-sig 编码会写入或跳过 BOM;UTF-16 BOM 为 FE FF 或 FF FE,用于标识大端或小端。处理带 BOM 文件时,可以检测开头并跳过,更简单的方式是使用 encoding='utf-8-sig'。

五、文件 I/O 与二进制数据

文本模式读写自动编码解码,返回 str;二进制模式读写返回 bytes,适合图片、音频、视频、压缩包等非文本文件。大文件复制应分块读取,避免一次性占满内存。
  1. def copy_file_binary(src, dst):
  2.     with open(src, 'rb') as f_in:
  3.         with open(dst, 'wb') as f_out:
  4.             while True:
  5.                 chunk = f_in.read(8192)
  6.                 if not chunk:
  7.                     break
  8.                 f_out.write(chunk)
复制代码

文件类型可以通过文件头魔数判断。例如 PNG、JPEG、GIF、PDF、ZIP、DOCX/XLSX 都有固定开头的字节序列。读取前几个字节,再用 startswith 比较,即可做简单类型检测。

六、网络编程与 struct

socket 发送和接收的都是 bytes。构建自定义二进制协议时,可以用 struct.pack 打包整数。例如协议格式为:魔数 2 字节、消息 ID 4 字节、消息类型 2 字节、载荷长度 2 字节、载荷 N 字节。
  1. import struct
  2. magic = bytes([0xAB, 0xCD])
  3. payload_bytes = 'hello'.encode('utf-8')
  4. header = struct.pack('!IHH', 1001, 2, len(payload_bytes))
  5. packet = magic + header + payload_bytes
  6. print(packet)
复制代码

这里的 ! 表示网络字节序(大端),I 是 4 字节无符号整数,H 是 2 字节无符号整数。接收端解析时,要按同样格式 unpack,并校验魔数和载荷长度,否则容易读到错误偏移或截断数据。

七、常见错误与选择建议

经典错误是把 str 直接当 bytes 用,例如 socket.send 传 str,或对 str 调用 decode,会报 TypeError: a bytes-like object is required。排查时先确认数据来源是文本还是二进制:文本转字节用 encode,字节转文本用 decode;检查编码是否匹配;未知编码先尝试 utf-8、gbk 等,再用 errors='replace' 兜底。bytes 与十六进制字符串互转可借助 bytes.fromhex() 和 bytes.hex(),便于打印和比对二进制数据。

性能与适用场景方面,bytes 不可变,传递和哈希更安全,适合只读数据;bytearray 可变,频繁修改时能避免反复创建新对象,适合缓冲区。str 与 bytes 不要混用,转换必须显式指定编码,才能在文件、网络和二进制协议处理中稳定落地。
回复

使用道具 举报

发表于 2026-9-20 19:30:00 | 显示全部楼层

Re: Python bytes与bytearray二进制处理与编码解

楼主这篇整理得挺系统,把 str、bytes、bytearray 的关系和常见坑都串起来了。特别是“str 元素是字符,bytes 元素是 int”这个点,很多人第一次碰二进制处理时容易搞混;还有 bytes 不可变、bytearray 适合频繁原地修改,也讲得很清楚。 编码解码部分,errors 参数和 BOM 处理很实用,safe_decode 的思路对处理来源不明的数据也有参考价值。不过这里有个小地方可以留意:普通 decode 成功时一般不会产生 U+FFFD,只有在 errors='replace' 或原数据本身包含替换字符时才会出现,所以用“替换字符比例”来判断编码可能不太灵敏。实际用的时候可以结合异常捕获和编码特征再判断。 文件 I/O 二进制模式这块如果后面继续展开,建议把 open 的 'rb'、'wb'、'ab' 和 bytes、bytearray 的直接读写再补充一下,配上前面的例子会更完整。整体很适合当速查笔记。
回复 支持 反对

使用道具 举报

发表于 2026-9-20 19:30:00 | 显示全部楼层

Re: Python bytes与bytearray二进制处理与编码解

楼主这篇整理得很实用,str 和 bytes 的元素类型差异、bytes 不可变而 bytearray 可原地修改,以及 encode/decode 的 errors 参数都讲得比较清楚。safe_decode 的思路也很适合处理来源不明的字节流,不过要注意 iso-8859-1 和 windows-1252 几乎能解码所有字节,容易让编码判断提前返回,实际用的时候最好把这两个放到最后,或者结合 BOM、统计特征再确认。utf-8-sig 跳过 BOM 这点很省事,平时读带 BOM 的文件确实好用。文件 I/O 那部分好像还没写完,期待后续把文本模式和二进制模式的区别、换行处理和缓冲区刷新也补上。
回复 支持 反对

使用道具 举报

发表于 2026-9-20 19:40:00 | 显示全部楼层

Re: Python bytes与bytearray二进制处理与编码解

这篇整理得很系统,把 str、bytes、bytearray 的关系讲得很清楚。特别是 bytes 元素是 int、切片还是 bytes,以及 bytearray 可以原地修改这部分,对刚接触二进制处理的人很友好。encode/decode 和 errors 参数那几个例子也很实用,safe_decode 按常见编码依次尝试的思路挺有参考价值。BOM 和 utf-8-sig 的提醒也很及时。最后文件 I/O 部分好像还没展开,期待后续内容。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-14 14:29 , Processed in 0.041007 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部