8.1 文件与目录——二进制数据¶
内容梗概¶
本节课是"文件与目录"一章的开篇,承接上一节文本文件读写的输入输出内容,转入二进制数据的学习。老师先介绍了本章的整体安排(二进制文件操作、BMP 解析、字符集与编码、目录操作),随后重点讲解了 Python 中表示二进制数据的两种类型:bytes 和 bytearray。课程详细解释了 bytes 字面值的显示规则(可打印 ASCII 字符与 \x 十六进制形式混合出现),并通过多个实例演示了二进制数据的创建、切片、hex()/fromhex() 转换和 index() 查找等序列操作。
知识点详解¶
本章内容安排(约 00:00 - 01:00)¶
- 上一节已讲过文本文件的读取与写入;本节重点转向二进制文件,将解析上节课用到的 BMP 文件。
- 顺便会讲字符集与编码问题(计算机领域绕不过去的问题),以及用 Python 遍历目录、重命名文件等目录操作(如批量整理照片)。
- Python 常被称为"脚本语言",遍历目录是最常见的辅助性需求之一;Windows / Linux / macOS 上的目录操作方式一致。
二进制数据的两种类型:bytes 与 bytearray(约 01:00 - 04:15)¶
- 之前讲数据类型基础和进阶时回避了二进制数据,放到文件这一节结合讲解,逻辑递进更顺畅。
- Python 中二进制数据有两种类型:
bytes:字节(复数),不可变序列,绝大多数情况下使用的类型。bytearray:可变序列,类比"元组 : 列表 = bytes : bytearray"的对应关系;少数需要手动修改二进制数据内容时才用到。
bytes 字面值的显示规则(约 04:16 - 15:30)¶
print一个 bytes 对象时,显示为b'...'的形式,小写b表示 Binary,这就是该类型的**字面值**。- 字面值以字节为单位,每个符号表示一个字节。字面值中混合存在两种形式:
- 可打印字符:字节的值能翻译成可打印的 ASCII 字符(含
\n、\t等可转义字符)时,直接显示该字符。例如字符0对应的字节显示为0。 \x十六进制形式:无法翻译成可打印字符时,直接以\x加该字节的十六进制值显示,如\x00。\x后面两个十六进制字符共表示一个字节(1 个十六进制字符 = 4 比特,2 个 = 8 比特)。- 为什么用十六进制而不用二进制/八进制表示字节(约 07:42):
- 纯二进制一个字节要写 8 个 0/1,太啰嗦;
- 八进制一个字符表示 3 个比特,8 比特除不尽 3,无法整齐对齐一个字节;
- 十六进制每 4 比特正好一个字符(0–F),两个字符合一个字节,表示简洁、对齐方便。因此所有计算机课程、WinHex 等工具都用十六进制显示二进制数据。
- 示例辨析:
a = b'\x00\x00\x00'与b = b'000'都是三个字节但**值不同**——前者每个字节十六进制为 0x00,后者每个字节是字符0的 ASCII 码 0x30。可通过b == c比较验证。 - 提问互动(约 16:11):
a含三个字符0、一个\x00、一个\n(换行,十六进制 0A),共 5 个字节;换行是可转义字符,打印时显示为\n而不是\x0a。 - 常见可转义字符对应的值:
\n(换行,0x0A)、\t(制表符/Tab,0x09)、空格(0x20)。
bytes 的创建方式(约 19:47 - 22:25)¶
- 直接用字面值赋值:
a = b'\x00\x00\x00'。 - 内置函数
bytes()转换: - 传入整数
n:创建包含n个全 0 字节的序列,如bytes(3)得到b'\x00\x00\x00'。 - 传入可迭代对象:如
bytes(range(3))得到b'\x00\x01\x02'。 bytearray不能用字面值直接创建(b'123'的类型永远是bytes),需要用bytearray(b'...')包裹字面值来构造;打印时会显示bytearray(b'...')以区分类型。- 实际很少用
bytearray:处理二进制数据大多是从文件读进来分析,或构造bytes直接写回文件,很少需要在内存中逐字节修改。
二进制数据的序列操作(约 24:04 - 31:30)¶
bytes/bytearray都是序列,之前学的序列操作(索引、切片、index查找等)全部可用。- 切片:如
bytes(range(10))[:5]得到b'\x00\x01\x02\x03\x04'。 .hex()方法(约 25:41):把二进制数据转成**字符串**,内容是其十六进制表示,如b.hex()得到'0001020304'。bytes.fromhex(s)(约 26:30):反向操作,接收十六进制字符串生成 bytes。- 字符串长度必须是 2 的整数倍(每两个字符一个字节),否则报
ValueError; - 字符只能是
0-9、A-F(十六进制字符),打H、中文等都会报错。 index():查找某个值在二进制序列中的下标,与之前做 Base64 编码练习时查字符索引的用法一样。- 顺带提及:之前"直男表白"的例子用
hex/fromhex会更方便,用ord/chr函数也可以。
示例与演示¶
- 定义
a = b'\x00\x00\x00',print(a)显示字面值、print(type(a))显示<class 'bytes'>。 - 比较
b'\x00\x00\x00'与b'000'是否相等(False),b'000'与b'\x30\x30\x30'是否相等(True),说明字符0对应 ASCII 码 0x30。 - 含 5 个字节的混合字面值示例:三个字符
0+\x00+\n,展示可打印字符与\x形式混合出现的效果。 bytes(3)创建 3 字节全 0 序列;bytes(range(3))创建b'\x00\x01\x02'。bytearray(b'123')创建可变序列,演示其与bytes打印形式的差异。- 序列操作综合示例:
bytes(range(10))切片取前 5 字节;b.hex()转十六进制字符串'0001020304';bytes.fromhex('2030ff')中 0x20 显示为空格、0x30 显示为0、0xFF 显示为\xff;index查找 0x00 的位置(索引 0)。 - 错误演示:
fromhex传长度为奇数的串、含H等非法十六进制字符的串,均抛ValueError。
重点与难点¶
- bytes 字面值的两种混合形式:可打印 ASCII 字符(含
\n、\t等转义字符)直接显示,不可打印字节显示为\x+ 两位十六进制。看到一串字面值时必须能数清到底有几个字节,这是本节反复强调的意识。 \x00(值为 0 的字节)与字符'0'(值为 0x30)完全不同,不能混淆。- 十六进制是表示二进制数据的标准形式:一个字节 = 8 比特 = 两个十六进制字符。
bytes不可变、bytearray可变;字面值b'...'创建出来的永远是bytes。fromhex()的参数长度必须是 2 的整数倍且只含合法十六进制字符。
关联内容¶
- 承接上一节(第 7 章)文本文件的读写与 BMP 转 ASCII 艺术练习;本节的二进制知识是下一节"二进制文件分析(BMP 解析)"的直接基础。
- 与"数据类型基础/进阶"中序列操作(索引、切片、
index)、字典等知识衔接;ord/chr函数在早期字符与数字转换练习中已出现。 - 提到上学期使用 WinHex 做文件恢复、查看硬盘数据的十六进制显示,与本节的十六进制表示一脉相承。
- 字符编码问题为 8.4 节"字符集与编码"埋下伏笔。