用 Python 一键把 ASC 文件转成 BLF(基于 python-can)
做车载/嵌入式 CAN 总线开发时,Vector 的 CANoe/CANalyzer/ canoe log 常用两种格式:
ASC (文本格式,人能看懂,但体积大、加载慢)和 BLF (二进制格式,体积小、加载快,CANoe 打开体验更好)。
本文分享一个不到 110 行的 Python 小工具,支持单个文件转换 和整个目录批量转换。
一、为什么要转 BLF?
| 对比项 | ASC | BLF |
|---|---|---|
| 类型 | 纯文本 | 二进制 |
| 体积 | 大(通常是 BLF 的 5~10 倍) | 小 |
| CANoe 加载速度 | 慢(大文件要等很久) | 快 |
| 可读性 | 记事本直接能看 | 需要工具 |
| 通用性 | 几乎所有工具支持 | Vector 系工具、python-can 支持 |
结论 :日常抓包、调试时 ASC 够用;但如果要长期归档 、发给同事分析 、或者在 CANoe 里打开几个 G 的日志,转成 BLF 体验会好很多。
二、环境准备
只需要一个依赖:python-can。
bash
pip install python-can
python-can 内置了
ASCReader和BLFWriter两个类,读写逻辑它都帮我们做好了,我们要做的只是"读出来再写进去"。
三、完整代码
保存为 asc_to_blf.py:
python
#!/usr/bin/env python
"""
ASC to BLF converter using python-can library.
用法: python asc_to_blf.py # 转换当前目录下所有 .asc 文件
python asc_to_blf.py <input.asc> # 转换单个 .asc 文件
python asc_to_blf.py <input.asc> <output.blf> # 指定输出文件名
依赖安装: pip install python-can
"""
import sys
import os
import glob
from pathlib import Path
def convert_asc_to_blf(asc_path, blf_path):
"""将单个 ASC 文件转换为 BLF 文件"""
import can
print(f"正在读取: {asc_path}")
msgs = []
with can.ASCReader(asc_path) as reader:
for msg in reader:
msgs.append(msg)
if not msgs:
print(f"警告: {asc_path} 中未找到任何 CAN 消息,跳过。")
return False
print(f"正在写入 {len(msgs)} 条消息到: {blf_path}")
with can.BLFWriter(blf_path) as writer:
for msg in msgs:
writer.on_message_received(msg)
print(f"转换完成: {asc_path} -> {blf_path}")
return True
def convert_all_asc_in_directory(directory):
"""批量转换目录下所有 .asc 文件"""
asc_files = glob.glob(os.path.join(directory, "*.asc"))
asc_files.extend(glob.glob(os.path.join(directory, "*.ASC"))) # 支持大写扩展名
asc_files = list(set(asc_files)) # 去重
if not asc_files:
print(f"在目录 {directory} 中未找到任何 .asc 文件")
return 0, 0
print(f"找到 {len(asc_files)} 个 ASC 文件")
print("-" * 50)
success_count = 0
fail_count = 0
for asc_path in asc_files:
blf_path = os.path.splitext(asc_path)[0] + ".blf"
try:
if convert_asc_to_blf(asc_path, blf_path):
success_count += 1
else:
fail_count += 1
except Exception as e:
print(f"转换失败: {asc_path} - {e}")
fail_count += 1
print("-" * 50)
print(f"批量转换完成: 成功 {success_count} 个, 失败 {fail_count} 个")
return success_count, fail_count
if __name__ == '__main__':
try:
import can
except ImportError:
print("错误: 未安装 python-can。请执行: pip install python-can")
sys.exit(1)
# 获取当前脚本所在目录
script_dir = os.path.dirname(os.path.abspath(__file__))
if len(sys.argv) >= 2:
# 命令行参数模式:支持单文件或指定目录
input_path = sys.argv[1]
if os.path.isdir(input_path):
# 指定了目录
success, fail = convert_all_asc_in_directory(input_path)
sys.exit(0 if fail == 0 else 1)
elif os.path.isfile(input_path):
# 指定了单个文件
if len(sys.argv) >= 3:
blf_path = sys.argv[2]
else:
blf_path = os.path.splitext(input_path)[0] + ".blf"
try:
if convert_asc_to_blf(input_path, blf_path):
sys.exit(0)
else:
sys.exit(1)
except Exception as e:
print(f"错误: {e}")
sys.exit(1)
else:
print(f"错误: 路径不存在 - {input_path}")
sys.exit(1)
else:
# 无参数:转换当前脚本所在目录下所有 .asc 文件
success, fail = convert_all_asc_in_directory(script_dir)
sys.exit(0 if fail == 0 else 1)
四、使用方法
脚本支持三种调用方式:
bash
# 1. 不带参数:批量转换脚本所在目录下的所有 .asc 文件
python asc_to_blf.py
# 2. 指定单个文件(输出同名 .blf)
python asc_to_blf.py demo.asc
# 3. 指定输入输出文件名
python asc_to_blf.py demo.asc output.blf
# 4. 传入目录:批量转换该目录下所有 .asc
python asc_to_blf.py D:\can_logs
运行效果:
找到 3 个 ASC 文件
--------------------------------------------------
正在读取: D:\can_logs\run1.asc
正在写入 128456 条消息到: D:\can_logs\run1.blf
转换完成: D:\can_logs\run1.asc -> D:\can_logs\run1.blf
正在读取: D:\can_logs\run2.asc
正在写入 98233 条消息到: D:\can_logs\run2.blf
转换完成: D:\can_logs\run2.asc -> D:\can_logs\run2.blf
--------------------------------------------------
批量转换完成: 成功 3 个, 失败 0 个
五、几个实现细节
1. 为什么要先 import can 再检查?
python
try:
import can
except ImportError:
print("错误: 未安装 python-can。请执行: pip install python-can")
sys.exit(1)
放在 __main__ 入口处做一次"前置体检",比让用户看到一堆红色 ModuleNotFoundError 友好得多。
2. 先全部读入再写入
代码里先把消息存进 msgs 列表再统一写 BLF,好处是可以先判断文件是否为空:
python
if not msgs:
print(f"警告: {asc_path} 中未找到任何 CAN 消息,跳过。")
return False
避免出现"生成了一个 0 字节的 BLF"这种尴尬情况。
⚠️ 小提示:这种写法会把所有消息驻留在内存里。如果是几个 G 的超大 ASC 文件 ,建议改成边读边写的流式方式(去掉
msgs列表,直接在循环里writer.on_message_received(msg))。
3. 兼容大写扩展名
python
asc_files = glob.glob(os.path.join(directory, "*.asc"))
asc_files.extend(glob.glob(os.path.join(directory, "*.ASC")))
asc_files = list(set(asc_files)) # 去重
在 Windows 上 glob 是大小写不敏感的,所以 set() 去重很关键,否则同一个文件会被处理两遍(Linux 上则能同时匹配到两种后缀)。
4. 退出码
脚本用 sys.exit(0/1) 返回退出码,方便在 CI、批处理脚本里判断执行结果:
bash
python asc_to_blf.py D:\can_logs
if %errorlevel% neq 0 (
echo 转换失败,请检查日志
)
六、小结
- 核心就两步:
can.ASCReader读 →can.BLFWriter写; - 支持单文件 / 目录批量两种模式,覆盖日常绝大多数场景;
- 代码短、零配置,丢到日志目录里双击运行就能用。
相关文章推荐:
- python-can 官方文档:https://python-can.readthedocs.io/
- BLF 格式说明:Vector Binary Logging Format