Python处理16进制byte数据:从字符串转换到文件存储的完整指南
本文详解Python中处理16进制byte数据的多种方法。针对byte转str再存文件导致的转义字符混乱问题,提供了手动解析\x格式的生成器方案及更简单的数字列表存储法。同时梳理了hex()与int()函数的进制转换语法,帮助开发者高效处理网络编程中的二进制数据持久化。
如何读取16进制byte数据
在进行网络编程时,常需处理非标准字符串的byte数据,例如类似b'\x00\xff\xfe\x01'的格式。这类数据属于16进制编码的byte类型,直接转为字符串虽无报错,但若再次转回bytes类型,往往会出现多余的双斜杠等异常现象,令人困扰。
a = b'\x00\xef\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x19\x39\xd9\x9d\xfdABCDabcd'
b = str(a)
print(b)
>>> b'\x00\xef\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x199\xd9\x9d\xfdABCDabcd'
print(bytes(b,'utf8'))
>>> b"b'\\x00\\xef\\xa2\\xa0\\xb3\\x8b\\x9d\\x1e\\xf8\\x98\\x199\\xd9\\x9d\\xfdABCDabcd'"若尝试将此类数据写入文件后再读取,结果依然不理想。原因在于写入时将其作为普通字符串处理,导致原始的二进制结构丢失,读取时无法还原。
# 写入data.txt
a = b'\x00\xef\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x19\x39\xd9\x9d\xfdABCDabcd'
with open('data.txt','w') as p:
p.write(str(a))
# 读取data.txt
with open('data.txt','r') as p:
line = p.readline()
print(line, type(line) == str)
>>> b'\x00\xef\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x199\xd9\x9d\xfdABCDabcd\\' True
print(bytes(line,'utf8'))
>>> b"b'\\x00\\xef\\xa2\\xa0\\xb3\\x8b\\x9d\\x1e\\xf8\\x98\\x199\\xd9\\x9d\\xfdABCDabcd\\\\'"分析ASCII码可知,问题核心在于\x字符被解析器误读为反斜杠与字母x的组合,从而以字符串形式存储,占用两个字节,破坏了原有的单字节表示。
鉴于\xnn格式本质应视为ASCII码处理,可编写特定的转义逻辑进行读取解析。
def readbytetxt(filename):
dic = {
'0': 0, '1': 1, '2': 2,
'3': 3, '4': 4, '5': 5,
'6': 6, '7': 7, '8': 8,
'9': 9, 'a': 10, 'b': 11,
'c': 12, 'd': 13, 'e': 14,
'f': 15,
}
with open(filename,'r') as p:
line = p.readline()
while line:
if line[-1] == '\n':
line = line[:-1]
i = 2
L = b''
while i+1 < len(line):
if line[i:i+2] == '\\x' and (line[i+2] in dic.keys()) and (line[i+3] in dic.keys()):
L += bytes([dic[line[i+2]]*16+dic[line[i+3]]])
i += 4
else:
L += bytes(line[i],'utf8')
i += 1
return L
line = p.readline()
print(readbytetxt('data.txt'))
>>> b'\x00\xef\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x19\x39\xd9\x9d\xfdABCDabcd'通过遍历字符串,识别\x标记,将后续两位16进制数转换为十进制整数,再解码为bytes对象,即可恢复常见的十六进制格式数据。
此外,还需处理其他转义字符如\\、\n等,否则仍会出现识别错误。改进后的函数支持多种常见转义字符,并采用生成器模式输出,提高了灵活性。
def readbytetxt2(filename):
dic = {
'0': 0, '1': 1, '2': 2,
'3': 3, '4': 4, '5': 5,
'6': 6, '7': 7, '8': 8,
'9': 9, 'a': 10, 'b': 11,
'c': 12, 'd': 13, 'e': 14,
'f': 15,
}
dic2 = {
'a': '\a', 'b': '\b',
'f': '\f', 'n': '\n',
'r': '\r', 'v': '\v',
'\'': '\'', '\"': '',
'\\': '\\',
}
with open(filename,'r') as p:
line = p.readline()
while line:
if line[-1] == '\n':
line = line[:-1]
i = 2
L = b''
while i+1 < len(line):
if line[i:i+2] == '\\x' and (line[i+2] in dic.keys()) and (line[i+3] in dic.keys()):
L += bytes([dic[line[i+2]]*16+dic[line[i+3]]])
i += 4
elif line[i] == '\\' and line[i+1] in dic2.keys():
L += bytes(dic2[line[i+1]],'utf8')
i += 2
elif line[i:i+4] == '\\000':
L += bytes('\000','utf8')
i += 2
else:
L += bytes(line[i],'utf8')
i += 1
yield L
line = p.readline()
a = b'\x00\xef\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x19\x39\xd9\x9d\xfdthe first line\n\r\a\b\t\\\f\'\"\v\b\n\000'
b = b'\xa0\xdf\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x19\x39\xd9\x9d\xfdthe second line\nn'
c = b'\xe0\xaf\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x19\x39\xd9\x9d\xfdthe third line\\'
with open('data.txt','w') as p:
p.write(str(a)+'\n')
p.write(str(b)+'\n')
p.write(str(c))
line = readbytetxt2('data.txt')
print([a for a in line])
>>> [b'\x00\xef\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x199\xd9\x9d\xfdthe first line\n\r\x07\x08\\t\\\x0c\'"\x0b\x08\n\x00', b'\xa0\xdf\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x199\xd9\x9d\xfdthe second line\nn', b'\xe0\xaf\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x199\xd9\x9d\xfdthe third line\\']经过上述优化,大部分编码形式的读取问题得以解决。
然而,还存在一种更简便的处理思路。既然根本问题在于字符串格式中复杂的转义规则难以理清,而byte本身即为16进制数字表示,那么只需存储数字即可。因此,可直接将byte数据转换为数字列表进行存储。
L = []
a = b'\x00\xef\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x19\x39\xd9\x9d\xfdthe first line\n\r\a\b\t\\\f\'\"\v\b\n\000'
print(a)
for each in a:
L.append(int(each))
with open('data.txt','w') as p:
p.write(str(L))
print(L)
>>> [0, 239, 162, 160, 179, 139, 157, 30, 248, 152, 25, 57, 217, 157, 253, 116, 104, 101, 32, 102, 105, 114, 115, 116, 32, 108, 105, 110, 101, 10, 13, 7, 8, 9, 92, 12, 39, 34, 11, 8, 10, 0]
with open('data.txt','r') as p:
line = p.readline()
print(b''.join([bytes([int(i)]) for i in line[1:-1].split(',')]))
>>> b'\x00\xef\xa2\xa0\xb3\x8b\x9d\x1e\xf8\x98\x199\xd9\x9d\xfdthe first line\n\r\x07\x08\t\\\x0c\'"\x0b\x08\n\x00'读取时,利用split方法分割数字列表,再逐个转换回bytes。这种方式避免了转义字符带来的歧义,确保数字对应什么byte就还原为什么byte,简单可靠。
Python的十六进制数
转换关系
十进制整数转十六进制整数使用hex()函数;十六进制整数转十进制整数使用int()函数。
同理,十进制整数转二进制整数使用bin()函数;十进制整数转八进制整数使用oct()函数。
hex() 函数
描述:hex() 函数用于将10进制整数转换成16进制,以字符串形式表示。
语法:
hex(x)
参数说明:x – 10进制整数
返回值:返回16进制数,以字符串形式表示。
int() 函数
描述:int() 函数用于将一个字符串或数字转换为整型。
语法:
class int(x, base=10)
参数说明:x – 字符串或数字。base – 进制数,默认十进制。
返回值:返回整型数据。
运算
对于十六进制整数,在进行运算前先转换成十进制整数,再对其进行运算,之后将运算结果转换回十六进制数。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









