核心结论:前缀"b"用于创建字节串对象,它以二进制形式存储数据,是Python处理文件I/O、网络通信等底层操作的基石。
一、基础定义
官方名称:字节串
核心功能:表示不可变的二进制数据序列(0-255的整数序列)。
语法形式:在字符串引号前加"b"或"B"
|
1
2
3
|
b'hello' # 字节串
b"world" # 同上
B'test' # 同上
|
二、数据类型特性对比
| 维度 |
普通字符串 (str) |
字节串 |
| 存储内容 |
Unicode字符 |
原始字节数据(0-255) |
| 长度单位 |
字符数 |
字节数 |
| 编码 |
已经解码,无需编码 |
需要指定编码才能转为文本 |
| 可打印性 |
直接显示字符 |
显示转义形式(如b'\xe4\xb8\xad') |
| 不可变性 |
不可变 |
不可变 |
| 类型检查 |
type('') is str |
type(b'') is bytes |
本质区别示例:
|
1
2
3
4
|
s = '中' # 长度1,包含一个Unicode字符
b = b'\xe4\xb8\xad' # 长度3,包含3个字节(UTF-8编码)
print(len(s)) # 1
print(len(b)) # 3
|
三、必须使用字节串的三大典型场景
1.文件I/O(二进制模式)
读写图片、音频、视频、压缩文件等非文本文件时,必须用字节串:
|
1
2
3
4
|
with open('image.jpg', 'rb') as f: # 注意'rb'表示二进制读
data = f.read() # 返回bytes对象
with open('copy.jpg', 'wb') as f:
f.write(data)
|
2.网络通信(socket编程)
网络协议传输的是原始字节流,而非文本:
|
1
2
3
4
5
6
|
import socket
sock = socket.socket()
sock.connect(('example.com', 80))
request = b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n'
sock.sendall(request) # 必须发送bytes
response = sock.recv(4096) # 返回bytes
|
3.加密与哈希运算
加密算法处理的是二进制数据:
|
1
2
3
4
|
import hashlib
md5 = hashlib.md5()
md5.update(b'secret') # 必须传入bytes
print(md5.hexdigest())
|
四、语法规则
正确声明方式
|
1
2
3
4
5
|
b'hello' # 单引号
b"world" # 双引号
b'''multi''' # 三单引号
B"""multi""" # 三双引号
b'\xe4\xb8\xad' # 转义序列
|
常见错误写法
- 混合使用编码字符
|
1
2
|
b'中文字符' # ? SyntaxError: bytes can only contain ASCII literal
b'\xe4\xb8\xad' # ? 正确:用十六进制表示UTF-8编码
|
- 字符串拼接错误
|
1
2
|
'text' + b'bytes' # ? TypeError: can't concat str to bytes
b'text' + b'bytes' # ? 正确
|
- 格式化不支持
|
1
|
b'hello {}'.format('world') # ? 字节串不支持.format()
|
五、类型转换方法
str → bytes(编码)
|
1
2
3
4
5
6
7
8
|
# 方法1:encode()
text = '你好世界'
byte_data = text.encode('utf-8') # b'\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c'
# 方法2:bytes构造函数
byte_data = bytes(text, 'utf-8')
byte_data = bytes(text, encoding='utf-8')
# 方法3:bytes字面量(仅限ASCII)
byte_data = b'hello'
|
bytes → str(解码
|
1
2
3
4
5
6
7
8
|
# 方法1:decode()
text = byte_data.decode('utf-8') # '你好世界'
# 方法2:str构造函数
text = str(byte_data, 'utf-8')
text = str(byte_data, encoding='utf-8')
# 处理解码错误
text = byte_data.decode('utf-8', errors='ignore') # 忽略错误字符
text = byte_data.decode('utf-8', errors='replace') # 用?替换
|
六、操作限制与替代方案
字节串不支持的字符串操作
|
1
2
3
4
5
6
7
|
b'hello'.upper() # ? 支持(仅ASCII)
b'hello'.lower() # ? 支持(仅ASCII)
b'hello'.strip() # ? 支持
# ? 以下操作不支持或不按预期工作:
b'hello {}'.format('world') # 不支持格式化
b'hello' + 'world' # 不能与str拼接
b'hello'.isalpha() # 非ASCII字符行为不同
|
替代方案
- 需要高级字符串操作?先解码
|
1
2
3
4
|
byte_data = b'hello \xe4\xb8\xad'
text = byte_data.decode('utf-8')
text = text.upper() # 使用str的方法
byte_result = text.encode('utf-8')
|
- 字节串专用方法
|
1
2
3
4
5
|
b'hello'.find(b'e') # ? 支持
b'hello'.replace(b'l', b'x') # ? 支持
b'hello'.split(b'e') # ? 支持
b'abc'.hex() # ? 转为十六进制字符串
bytes.fromhex('616263') # ? 从十六进制创建
|
七、实际应用案例
案例1:二进制文件复制器
|
1
2
3
4
5
6
7
8
9
10
|
def copy_binary_file(src, dst, chunk_size=8192):
"""高效复制二进制文件"""
with open(src, 'rb') as f_src, open(dst, 'wb') as f_dst:
while True:
chunk = f_src.read(chunk_size) # 读取bytes块
if not chunk:
break
f_dst.write(chunk)
# 使用示例
copy_binary_file('original.jpg', 'backup.jpg')
|
案例2:HTTP请求客户端
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import socket
def simple_http_request(host, path='/'):
"""发送简单的HTTP GET请求"""
# 构建HTTP请求(必须是bytes)
request = f"GET {path} HTTP/1.1\r\nHost: {host}\r\n\r\n"
request_bytes = request.encode('utf-8')
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, 80))
try:
sock.sendall(request_bytes)
response = b''
while True:
chunk = sock.recv(4096)
if not chunk:
break
response += chunk
# 分离头部和主体
header, _, body = response.partition(b'\r\n\r\n')
print("Response Header:")
print(header.decode('utf-8', errors='ignore'))
return body
finally:
sock.close()
# 使用示例
content = simple_http_request('example.com', '/')
|
案例3:文件哈希校验工具
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import hashlib
def calculate_file_hash(filepath, algorithm='md5'):
"""计算文件的哈希值"""
hash_func = hashlib.new(algorithm)
with open(filepath, 'rb') as f: # 二进制模式读取
while True:
chunk = f.read(8192) # 分块读取bytes
if not chunk:
break
hash_func.update(chunk)
return hash_func.hexdigest()
# 使用示例
print(f"MD5: {calculate_file_hash('document.pdf', 'md5')}")
print(f"SHA256: {calculate_file_hash('document.pdf', 'sha256')}")
|
关键要点总结
- 记住黄金法则:涉及二进制数据(文件/网络/加密)时,用bytes;涉及文本处理时,用str
- 编码解码桥梁:.encode() 将 str 转为 bytes,.decode() 将 bytes 转为 str
- 错误处理:解码时始终考虑 errors 参数(ignore/replace)
- 性能考虑:大文件操作时,分块读写bytes更高效
|