3、文件与目录操作自动化:使用os和shutil模块批量处理固件、日志、配置文件
做嵌入式开发,说白了就是跟文件打交道。固件要烧录、日志要分析、配置文件要修改。这些活儿,一天重复几十次,手都酸了。
我刚开始做嵌入式那会儿,每天手动复制固件、重命名日志文件、修改配置参数。有一次,我连续改了20个配置文件,结果漏了一个,导致整批设备烧录失败。嗯,从那以后,我就下定决心——能用脚本干的,绝不动手。
3.1 os模块:文件操作的瑞士军刀
os模块是Python自带的,不需要额外安装。它提供了操作文件和目录的基本方法。我个人习惯,写脚本前先导入它:
import os
3.1.1 路径拼接与检查
嵌入式项目里,路径经常变。今天在Windows上开发,明天可能就切到Linux服务器。直接写死路径?那是在给自己挖坑。
我建议用os.path.join()来拼接路径。它会自动处理不同系统的分隔符:
# 不推荐
path = "C:/firmware/v1.2/bin/"
# 推荐
base_dir = "/home/project/firmware"
version = "v1.2"
bin_path = os.path.join(base_dir, version, "bin")
print(bin_path) # 输出: /home/project/firmware/v1.2/bin
检查文件是否存在,用os.path.exists()。我在项目中遇到过,固件编译失败但脚本没检查,结果烧录了旧版本。从那以后,我每次操作前都会加一句检查:
firmware_file = os.path.join(bin_path, "app.bin")
if not os.path.exists(firmware_file):
print(f"错误:固件文件 {firmware_file} 不存在!")
exit(1)
os.path.isdir() 判断是否是目录,os.path.isfile() 判断是否是文件。别搞混了,否则脚本会报错。
3.1.2 遍历目录与文件过滤
批量处理固件时,经常需要遍历某个目录下的所有文件。比如,我要找出所有.bin结尾的固件文件:
firmware_dir = "./output"
for root, dirs, files in os.walk(firmware_dir):
for file in files:
if file.endswith(".bin"):
full_path = os.path.join(root, file)
print(f"找到固件:{full_path}")
os.walk()会递归遍历所有子目录。你想想看,如果手动找,几十个文件夹翻下来,眼睛都花了。用脚本,一秒搞定。
3.1.3 重命名与移动文件
日志文件命名,我习惯加上时间戳。这样方便排查问题:
import time
log_file = "device.log"
timestamp = time.strftime("%Y%m%d_%H%M%S")
new_name = f"device_{timestamp}.log"
os.rename(log_file, new_name)
print(f"日志已重命名为:{new_name}")
移动文件到归档目录,用os.replace():
archive_dir = "./archive"
if not os.path.exists(archive_dir):
os.makedirs(archive_dir)
os.replace(new_name, os.path.join(archive_dir, new_name))
os.rename() 在不同文件系统间可能会失败。跨分区移动文件时,建议用 shutil.move(),更稳定。
3.2 shutil模块:高级文件操作利器
shutil模块是os的补充。它提供了复制、移动、删除目录等高级功能。说白了,os管的是「单个文件」,shutil管的是「一堆文件」。
3.2.1 复制文件与目录
备份固件是常规操作。我每次烧录前,都会自动备份当前版本:
import shutil
src = "./firmware/app.bin"
backup_dir = "./backup"
os.makedirs(backup_dir, exist_ok=True)
# 复制单个文件
shutil.copy2(src, backup_dir) # copy2 保留文件元数据
# 复制整个目录
shutil.copytree("./config", "./config_backup", dirs_exist_ok=True)
我曾经因为没备份,误删了配置文件,结果花了半天重新配置。现在我的脚本里,备份是第一步。
3.2.2 删除目录
清理临时文件时,os.remove()只能删文件,删目录要用shutil.rmtree():
temp_dir = "./temp_build"
if os.path.exists(temp_dir):
shutil.rmtree(temp_dir)
print(f"临时目录 {temp_dir} 已删除")
rmtree() 删除不可恢复!我建议在删除前先打印路径,确认无误再执行。或者加个确认提示。
3.2.3 移动与归档
项目交付时,需要把固件、日志、配置文件打包。用shutil.make_archive()一步到位:
# 打包整个输出目录
archive_name = shutil.make_archive(
base_name="./release_v1.2",
format="zip",
root_dir="./output"
)
print(f"归档文件已生成:{archive_name}")
支持的格式有zip、tar、gztar等。我一般用zip,兼容性最好。
3.3 实战:批量处理固件与日志
光说不练假把式。下面是我实际项目中用过的脚本,处理固件发布流程:
import os
import shutil
import time
def process_firmware_release(version):
"""处理固件发布:备份、重命名、归档"""
# 1. 定义路径
base_dir = "./firmware"
release_dir = os.path.join(base_dir, version)
backup_dir = os.path.join(base_dir, "backup", version)
archive_dir = "./archive"
# 2. 检查源目录
if not os.path.isdir(release_dir):
print(f"错误:版本目录 {release_dir} 不存在")
return False
# 3. 创建备份
print(f"正在备份到 {backup_dir}...")
shutil.copytree(release_dir, backup_dir, dirs_exist_ok=True)
# 4. 重命名固件文件,加上时间戳
timestamp = time.strftime("%Y%m%d")
for file in os.listdir(release_dir):
if file.endswith(".bin"):
old_path = os.path.join(release_dir, file)
new_name = f"{version}_{timestamp}_{file}"
new_path = os.path.join(release_dir, new_name)
os.rename(old_path, new_path)
print(f" 重命名:{file} -> {new_name}")
# 5. 打包归档
os.makedirs(archive_dir, exist_ok=True)
archive_name = os.path.join(archive_dir, f"firmware_{version}_{timestamp}")
shutil.make_archive(archive_name, "zip", release_dir)
print(f"归档完成:{archive_name}.zip")
return True
# 使用示例
if __name__ == "__main__":
process_firmware_release("v2.1.0")
3.4 避坑指南
做文件操作,坑不少。我踩过的,列出来给你参考:
- 路径编码问题: 中文路径在Windows上可能报错。我建议统一用英文命名,或者在脚本开头加
# -*- coding: utf-8 -*-。 - 权限不足: 删除或移动文件时,可能遇到权限错误。用
try...except捕获PermissionError,并给出友好提示。 - 文件被占用: 日志文件可能被其他进程打开。操作前先检查文件是否可写,用
os.access()判断。 - 硬编码路径: 别把路径写死在代码里。用
os.getcwd()获取当前目录,或者用配置文件管理路径。
我曾经在服务器上跑脚本,忘了检查磁盘空间,结果归档时磁盘满了,整个构建流程崩溃。现在我的脚本里都会加一句磁盘检查:
import shutil
# 检查磁盘剩余空间(单位:字节)
total, used, free = shutil.disk_usage("/")
print(f"磁盘剩余空间:{free // (1024**3)} GB")
if free < 500 * 1024 * 1024: # 小于500MB就报警
print("警告:磁盘空间不足,建议清理!")
3.5 总结
os和shutil这两个模块,是嵌入式文件操作自动化的基石。说白了,你只要掌握:
os.path处理路径os.walk遍历目录shutil.copy2复制文件shutil.rmtree删除目录shutil.make_archive打包归档
这五个功能,就能覆盖90%的日常需求。剩下的10%,遇到问题再查文档,完全来得及。
下一章,我会讲如何用subprocess模块自动化编译和烧录流程。到时候,你连IDE都不用打开了,一个脚本全搞定。