查找bag解析报错:“UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0x8b in position 59: invalid start byte”
在针对指定topic执行解析bag包的时候,有的bag提示:UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0x8b in position 59: invalid start byte。
出问题的代码是ros的库文件:lib/python3.7/site-packages/rosbag/bag.py。然后进行debug:
方法1:找出bag中是否有非法的字符
首先了解编码/解码:为了显示特殊字符与汉字,会将其按照协议编码。如下例子:
# 执行编码,查看'失败 123abc'会编成什么:
byte_string = '失败 123abc'
uni_string = repr(byte_string)
print(uni_string)
# 执行解码,查看字符会解码成什么:
byte_string =b'\xe5\xa4\xb1\xe8\xb4\xa5'
new_by_string = byte_string.decode('utf-8')
print(new_by_string)
运行结果:
# '失败 123abc'会编码为如下。明显数字与英文不会被编码
'\xe5\xa4\xb1\xe8\xb4\xa5 123abc'
# b'\xe5\xa4\xb1\xe8\xb4\xa5'会被解码为中文:
失败
根据上边的例子,也就是说bag中有特殊字符解码错误。
在bag.py中添加调试代码,确实发现:\x98\xa8\xff\x86\xfa\x7f,
这种无法解码的字符。但是查找发布topic的源码,并没有打印非法字符或者异常字符。
方法2:对比运行ok的镜像,查看问题原因。
恢复镜像的版本,执行ok,不会报错。对比问题镜像与ok的镜像。问题镜像中lib/python3.7/site-packages/rosbag/bag.py为2614行,ok的镜像中为2938行。明显不一致。所以猜测是rosbag库文件的问题,对于部分字符encode失败。
结论:rosbag库文件会导致encode报错。
后续:为了找出2个库中编码的区别,修改bag.py,将全部的data输出,将有0x98的地方都打印出来:
cat error_msg.txt | grep -o ".\{0,20\}x98.\{0,20\}"
查看二者的解析结果是否有区别。结果是没有区别的。这就有问题了。
取出ok镜像输出的任意几处编码:
b'\x93\x01\x00\x00^\xe4ed\x14\r\xb30\x00\x00\x00\x00\xe3\x00\x00\x00\x00A\x00\x00\x00[INF]'
b'\x98\x01\x00\x00_\xe4ed\xe6\x90\xbf\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01/\x00\x00\x00 p'
执行解码:
byte_string = b'\x98\x01\x00\x00_\xe4ed\xe6\x90\xbf\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01/\x00\x00\x00 p'
new_by_string = byte_string.decode('utf-8')
结果还是报错:
UnicodeDecodeError: 'utf8' codec can't decode byte 0x98 in position 0: invalid start byte
查找资料,说这些二进制文件并不是可以编码解码的内容。可能是 ROS Bag 文件格式中的 Index Data(索引数据)或者 Connection Header(连接头)等二进制数据。这些数据是以机器人操作系统 (ROS) 中定义的二进制格式存储的,并不是文本字符串形式。
具体来说,Index Data 是指用于记录 ROS Bag 中所有消息的位置、时间等元数据的数据结构。而 Connection Header 则是指在 ROS 中用于描述话题通信方式和参数的字典数据结构。这些数据都是以 C++ 语言定义的二进制格式存储的,因此并不能直接使用 Python 或其他编程语言的字符串解码方法进行解析。