如何正确拆分DLT日志文件并保留消息头以适配dlt-viewer解析
解决DLT文件拆分后dlt-viewer无法解析的问题
问题根源
你用readlines(16384)按固定字节数切割DLT文件的方式,会破坏DLT的固有结构:
- DLT文件开头有16字节的存储头(Storage Header),dlt-viewer依赖这个头识别文件格式
- 每个DLT消息是变长结构(消息头+负载),固定字节切割大概率会截断完整消息,导致解析失败
解决方案一:按完整DLT消息拆分并保留存储头
步骤1:提取原始DLT文件的存储头
先从main.dlt开头读取16字节的存储头,这是每个合法DLT文件必须的标识。
步骤2:按完整消息读取并拆分
修改Python代码,按DLT消息的实际长度读取完整消息,累计到接近16KB时写入临时文件,且每个临时文件开头先写入存储头。
修改后的代码示例:
import struct def read_dlt_storage_header(file_obj): # 读取DLT固定16字节的存储头 return file_obj.read(16) def read_dlt_message(file_obj): # 读取DLT消息头前4字节,解析消息总长度 msg_header_prefix = file_obj.read(4) if not msg_header_prefix: return None # 从消息头第3-4字节(大端序)获取消息总长度 msg_length = struct.unpack('>H', msg_header_prefix[2:4])[0] # 读取剩余的消息内容 msg_rest = file_obj.read(msg_length - 4) if len(msg_rest) != msg_length - 4: return None # 消息不完整,直接丢弃 return msg_header_prefix + msg_rest def split_dlt_file(input_path, chunk_size=16384): storage_header = None with open(input_path, 'rb') as f: storage_header = read_dlt_storage_header(f) if not storage_header: print("无效的DLT文件,缺少存储头") return chunk_messages = [] current_size = 0 temp_file_index = 1 while True: msg = read_dlt_message(f) if not msg: # 处理剩余的消息 if chunk_messages: with open(f'temp_{temp_file_index}.dlt', 'wb') as temp_f: temp_f.write(storage_header) for m in chunk_messages: temp_f.write(m) temp_file_index += 1 break msg_size = len(msg) # 如果加入当前消息会超过设定的块大小,先写入当前块 if current_size + msg_size > chunk_size and chunk_messages: with open(f'temp_{temp_file_index}.dlt', 'wb') as temp_f: temp_f.write(storage_header) for m in chunk_messages: temp_f.write(m) temp_file_index += 1 chunk_messages = [] current_size = 0 chunk_messages.append(msg) current_size += msg_size # 执行拆分 split_dlt_file('main.dlt')
解决方案二:跳过拆分,直接实时过滤
如果不需要生成中间文件,直接用管道将dlt-receive的输出传给dlt-viewer实时处理,避免拆分带来的问题:
dlt-receive <IP> <PORT> | dlt-viewer -s -csv -f <FILTER NAME> -c - results.csv
这里的-表示从标准输入读取数据,无需生成main.dlt和临时文件。
补充:补全已有临时文件的存储头
如果已经有拆分好的临时文件,且确认文件内的消息是完整的,只是缺少存储头,可以从main.dlt提取前16字节的存储头,批量给临时文件添加:
# 提取原始存储头 with open('main.dlt', 'rb') as f: storage_header = f.read(16) # 给temp.dlt添加存储头 with open('temp.dlt', 'rb') as f: content = f.read() with open('fixed_temp.dlt', 'wb') as f: f.write(storage_header) f.write(content)
注意:如果临时文件内的消息已被截断,即使添加存储头也无法正常解析。
内容的提问来源于stack exchange,提问作者DonnyFlaw
相关产品推荐
相关产品推荐

