用 Python 一键把 ASC 文件转成 BLF(基于 python-can)

用 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 写;
  • 支持单文件 / 目录批量两种模式,覆盖日常绝大多数场景;
  • 代码短、零配置,丢到日志目录里双击运行就能用。

相关文章推荐:

相关推荐
leisoo80972 小时前
融资融券数据怎么查两融指标含义与杠杆观察方法 IG50免费开源股票数据API接口
开发语言·jvm·数据库·python·json
Patrick在香港2 小时前
同一份脚本,mac 正常 Windows 乱码:open() 默认编码实测(附 3.15 终局)
utf-8·windows·python·macos·跨平台·编码·标准库
勿信日志2 小时前
Playwright 元素定位:一个 width>50 过滤器把 42px 的输入框删掉了
python
larance2 小时前
[菜鸟教程] 机器学习教程十课-Python 机器学习应用
人工智能·python·机器学习
栖凤2 小时前
Java 的 try-catch 在 Agent 里失效了,我用了 5 个模式才兜住
java·前端·python
Yyyyyy~2 小时前
【python】函数
python
金銀銅鐵2 小时前
[Java] 借助GUI展示class文件的版本号
后端·python·ai编程
外收内放2 小时前
Python基础语法练习题(62原始版本及其优化版本)
开发语言·python
棉猴3 小时前
玩游戏学Python4-字符串
python·游戏·字符串·pygame·玩游戏