大家好,我是杂烩君。
本次介绍一个极致轻量化的嵌入式存储方案 ——UTFS(μTFS,micro TAR File System)。
UTFS简介
UTFS项目地址:https://github.com/clisystems/utfs
MIT 开源协议
UTFS 是一款类 TAR 归档、面向扁平字节寻址存储的极简存储层,不是完整带目录、日志、磨损均衡的通用文件系统。
其定位是手写固化结构体的标准化替代方案。
UTFS的特点:
体积极小:仅utfs.c + utfs.h两个源码文件,纯 C99 实现;
移植门槛极低:只需要实现sys_read、sys_write两个底层读写函数;
零动态内存:全程无malloc/free,全部静态内存,不占用堆;
向前兼容:后续新增参数文件,不会破坏原有存储布局,升级不丢旧数据;
极低存储开销:每个文件仅 24 字节固定头部,数据无填充、无对齐浪费;
UTFS 不是 FatFS / LittleFS。它不做目录树、不做 journaling、也不做磨损均衡:
持久化的坑
嵌入式开发中,参数持久化常见的坑:
- 直接写固定偏移 EEPROM/Flash,新增配置就要全量改存储布局,旧固件数据直接报废;手写结构体固化,多组参数分开存储,地址管理混乱,断电校验全靠自己造轮子;引入 FatFS/LittleFS,ROM 占用大、必须堆内存,AVR、STM8 这类小 RAM 芯片直接跑不动;
很多产品的真实需求其实很朴素:
- 上电把几块配置读进 RAM运行中改结构体字段合适的时候整表写回 EEPROM / Flash
这时候如果硬上完整文件系统,目录、权限、长文件名这些给人看的能力,往往用不上,代码和 RAM 却先涨一截。
反过来,继续手搓一个巨型 struct 钉在 0x0000,短期最快,长期最容易在加字段那天翻车。
手搓固定偏移 vs UTFS
左边那种布局,每个字段的地址都是产品契约的一部分;
右边 UTFS 的思路是:
每个文自带 24 字节头,按名字匹配,数据背靠背排布。以后加一个 calib,旧文件还是按名字找,而不是全员挪偏移。
demo:Linux PC 快速验证
cd Examples/gcc_linux
make
./main.bin -v
整体使用逻辑:
utfs_set + utfs_register:把本地 RAM 结构体和文件名绑定注册;
utfs_load:上电从 EEPROM/Flash 读取所有注册数据到 RAM;
utfs_save:参数修改后,一次性全量写入持久化介质。
UTFS 到底长什么样
名字可以记成 micro TAR File System(μTFS / uTFS)。灵感来自 TAR:Header + Data 重复拼接。
桌面 TAR 头是 512 字节一块,嵌入式扛不住,也用不上用户/用户组/权限那一套。
UTFS 把头压到 24 字节,后面紧跟数据,文件之间没有 padding。
最小闭环:register → load → save
UTFS 的使用节奏和传统 open/read/write/close不太一样。它更像:
一次性登记关心的文件,整表加载,整表保存。
UTFS 生命周期
典型写法可以:
utfs_init(false);
utfs_set(&sysfile, "system", &sysdata, sizeof(sysdata));
utfs_register(&sysfile, UTFS_NOFLAGS, UTFS_NOOPT);
utfs_set(&appfile, "appdata", &appdata, sizeof(appdata));
utfs_register(&appfile, UTFS_NOFLAGS, UTFS_NOOPT);
utfs_load();
if (utfs_file_signature(&appfile) != 0xABCD) {
memset(&appdata, 0, sizeof(appdata));
utfs_file_signature_set(&appfile, 0xABCD);
appdata.test_value = 1234; // 首启默认值
}
/* 业务里照常改 RAM 里的结构体……需要落盘时: */
utfs_save();
登记要持久化的东西,整表装进 RAM,改完再整表交回去。
中间业务代码不用围着文件系统 API转,继续写结构体字段就行。
移植缝也刻意留得很窄:库自己不做 I/O,实现两个函数就行:
uint32_t sys_write(uint32_t address, void *ptr, uint32_t length);
uint32_t sys_read (uint32_t address, void *ptr, uint32_t length);
EEPROM、片内 Flash、外部 SPI/I²C Flash,只要能按地址读写字节,就能接。
总结
UTFS 适合的场景:
- 仅存储少量配置结构体(≤5 组参数),不需要日志、大文件存储;小容量存储:1KB~16KB EEPROM、片内 Flash 参数分区;
欢迎大家在评论区聊聊,交流一下你的看法~
129