简介面向 Windows 64 位环境下进行 ESP32 开发的工程师这份资源提供了 i686-w64-mingw32 工具链编译的 mklittlefs 命令工具作为 MinGW-w64 交叉编译链的产物免去自行构建交叉编译环境的繁琐。该工具用于创建与管理 LittleFS 文件系统映像LittleFS 专为微控制器等资源受限设备设计借助它可高效生成 ESP32 闪存所需的文件系统镜像并集成到固件烧录流程。压缩包共 2 个文件包括可独立运行的 exe 主程序和用于描述版本与配置信息的 json 文件整体仅 325KB轻量便携。已有 312 人学习下载适合熟悉 ESP-IDF、需要处理 LittleFS 分区或自定义固件部署的嵌入式开发者尤其适合需要维护多个固件版本或搭建自动化构建流程的团队。通过该工具可完成文件系统的格式化、镜像构建与内容更新减少手工操作和部署错误加速 ESP32 项目的启动加载与版本维护。1. 在 Windows 上给 ESP32 配 mklittlefs先搞清楚这是个啥在 Windows 上做 ESP32 开发最绕不开的需求就是把网页资源、配置项、证书文件这些非代码内容整体放进 Flash 分区里。ESP-IDF 自带的很多工具默认面向 Linux 和 macOS到了 Windows 上要么需要自己折腾编译要么干脆没有可执行文件。mklittlefs 就是一个专门将本地目录打包成 LittleFS 镜像的命令行工具而这个i686-w64-mingw32.mklittlefs-c41e51a.200706目标版本就是通过 MinGW-w64 交叉编译出来的 Windows 可执行程序用来解决 Windows 上没有原生二进制的问题。它适合所有在 Windows 平台上把 LittleFS 分区做成镜像烧给 ESP32 的开发者尤其是带 Web Server、需要预置证书或掉电保存配置的中大型项目。先把这个工具是什么、为什么存在搞清楚后面烧录、挂载和排错才会顺。2. 先搞懂 LittleFS 和 mklittlefs镜像工具到底在替你做什么很多拿到 mklittlefs 的人第一反应是“这不就是个压缩打包工具吗”结果真用起来才发现如果不懂 LittleFS 的分区布局和镜像机制连参数都不敢乱填。这一章先把原理层面的东西讲透后面你才知道每个参数在调什么。2.1 LittleFS 的三个关键特性掉电安全、磨损均衡、目录遍历LittleFS 是专门为小容量嵌入式 Flash 设计的日志型文件系统。我在 ESP32 项目里对比过 SPIFFS 和 FAT最终选择 LittleFS 基本是这三个原因。掉电安全是它最被看重的特性。平时开发时经常调试到一半直接拔电FAT 遇到这种操作往往需要完整扫描才能恢复SPIFFS 则可能出现根目录损坏。LittleFS 通过写入时复制Copy-on-Write和元数据日志让系统在任意时刻崩溃都只会丢掉最后正在写入的那一笔数据旧文件仍然是完整的。这一点在温控设备、物联网网关这些不能随时停机的场景里非常重要。磨损均衡决定了 Flash 的寿命。SPIFFS 的磨损均衡实现比较粗糙如果频繁更新同一个文件那块区域容易被磨穿。LittleFS 会把擦写操作均匀散布到整个分区让单片机的 Flash 达到标称的十万次左右的擦写寿命。这个特性在做日志记录、循环覆盖配置的时候价值很大。目录遍历能力是相对于 SPIFFS 的优势。SPIFFS 的目录结构非常扁平要模拟子目录得靠路径拼接的约定。LittleFS 有真正的目录项支持mkdir、rename、opendir这些标准接口。比如我在做带 Web 前端的上位机页面时/data/style/和/data/script/分目录存放在代码里用opendir就能直接递归列出逻辑很自然。从选型角度讲只要不是过于老旧的 SDKESP-IDF 目前对 LittleFS 的支持都算稳定这也是我推荐你使用 mklittlefs 而不是继续用 mkspiffs 的主要原因。如果你还在用 SPIFFS那是时候考虑迁移到 LittleFS 了。2.2 为什么 ESP32 不能直接往 Flash 里写文件这个疑问在我第一次接触时也出现过“既然 LittleFS 是文件系统为什么不能在设备上直接创建文件非要先在电脑上生成一个镜像文件”原因在于 ESP32 的 Flash 内容是按分区表管理的。烧录固件时整个 Flash 被划分成若干分区NVS 分区存设备参数OTA 分区放固件data 分区放文件系统。LittleFS 驱动在挂载时必须知道自己被放在哪个偏移地址、区块大小是多少这些都与分区表严格绑定。如果要让主控程序在运行时第一次启动时自己去格式化分区不仅多出几十条 C 代码和初始化时间还会遇到“系统自动格式化后预置文件从哪来”的问题。工厂出货的固件总不能靠 UART 一个一个文件传进去。所以正确做法是在 PC 端用 mklittlefs 把整个目录树编成一块二进制镜像烧录到 data 分区对应的 Flash 偏移位置。这样出厂时就带有确定的文件内容设备启动后 LittleFS 直接挂载就能用不用再跑一遍 mkfs 流程。另一个好处是 OTA 切换时方便做版本管理。固件包里同时携带 app.bin 和 filesystem.bin升级时把两块数据一起写入对应分区所有文件内容都是已知且可校验的。这个机制决定了 mklittlefs 的核心价值它生成的不是简单的“大文件”而是一个带 LittleFS 元数据、目录索引和文件数据的完整文件系统快照。2.3 mklittlefs 的出身与二进制目标i686-w64-mingw32 意味着什么先从命名看这个包的背景。i686表示目标 CPU 架构是 32 位 x86w64-mingw32是 MinGW-w64 工具链的命名风格表明这是一个 Windows 原生程序c41e51a.200706则对应源码提交哈希和构建日期。这种命名方式在嵌入式工具链里非常常见意思是“这次构建对应的代码版本是 c41e51a发布于 2020 年 7 月 6 日前后”。你可能会有疑问现在 Windows 基本都是 64 位了为什么还发布 32 位版本这并不奇怪。很多发布者习惯用 i686 目标编译命令行工具因为 32 位程序在 64 位 Windows 上通过 WoW64 子系统可以正常运行兼容面更宽。实际使用中如果你只是跑命令不用太担心 32 位性能问题生成镜像的速度瓶颈基本在 Flash 读写和文件数量上架构影响很小。选择用预编译二进制而不是自己拉源码编译对我来说有几个理由。一是快解压就能用二是不用折腾 MSYS2、MinGW 环境三是这个版本通常与特定 LittleFS 驱动版本绑定只要参数匹配就能生成能被目标固件识别的镜像。缺点也清楚它不是官方直接发布的所以需要多一些验证步骤。后面的章节我会带你做环境自检和第一次试运行确保拿到的二进制是可用的。3. 在 Windows 上拿到 mklittlefs版本确认与环境自检拿到压缩包之后不要急着跑去生成镜像。Windows 下的命令行工具坑不少尤其是这种预编译的 exe经常栽在环境而不是工具本身。这一章带你做三件事确认系统兼容性、补好运行库、看 help 输出确认参数。3.1 先确认你的系统环境和这个包是否兼容第一步是确认当前 Windows 的架构。别以为所有 64 位系统都能跑所有 32 位包还要看是不是被精简过的系统。用命令查看wmic os get osarchitecture输出应该是64-bit或32-bit。如果是 64 位运行 i686 编译的 exe 基本没有兼容性障碍。如果你的系统是 32 位那更没问题这个包可以直接用。接下来把 exe 放到一个没有空格和中文的路径下。我见过有人把 mklittlefs.exe 放在C:\Program Files (x86)\...下写命令时被空格截断搞了半个小时以为是工具问题。我自己的习惯是在 C 盘建一个C:\tools\mklittlefs\把 exe 和依赖 DLL 都放进去再把这个目录加到 PATH 环境变量里。这样后续脚本不用写一长串绝对路径。这里有一个易被忽略的点如果你从压缩包里解压出来文件确实叫mklittlefs.exe但它的实际大小可能只有几十 KB。这并不是坏了而是它动态链接了其他运行库。真正的逻辑代码不都在这一个 exe 里。3.2 跑起来之前先解决 MinGW 运行库依赖很多人双击 exe 发现报错“缺少 libgcc_s_dw2-1.dll”或者“缺少 libwinpthread-1.dll”然后就以为下载包不完整。其实这只是因为这个版本用了动态链接的 MinGW 运行库。第一次见到这个报错时我也有点蒙后来才知道这些 DLL 本来就需要与 exe 一同分发。解决方式按顺序试。先看压缩包里是不是有libgcc_s_dw2-1.dll、libwinpthread-1.dll这些文件。如果只有 exe可以去 MinGW-w64 的运行时目录里取常见位置是C:\mingw32\bin或者 MSYS2 的\mingw32\bin。把对应 DLL 复制到 exe 同目录确保 exe 启动时能在当前目录找到。还有一种更省心的做法去找静态编译的版本。它的体积会大一些通常一两百 KB但不再依赖外部 DLL放到哪都能跑。如果你不想在每台电脑上都配一次 DLL静态版本是更好的选择。需要注意预编译的 exe 没有数字签名Windows Defender 或第三方杀毒软件可能直接把它隔离。现象就是文件解压后还在但一运行就提示找不到文件或者“操作已被管理员阻止”。这不是工具的问题是杀毒软件对未签名二进制的谨慎。处理办法是把 mklittlefs 所在目录加入排除项或者被隔离后手动恢复。恶意工具不会长得这么像命令行参数但你仍然要从可信来源获取这个 exe。3.3 第一件事是看 help从输出里读默认参数环境准备好后先运行帮助命令。在 cmd 或 PowerShell 中切到工具目录执行mklittlefs.exe -h正常的话会输出类似下面的文本不同版本可能措辞略有差异usage: mklittlefs [-s size] [-b block_size] [-p page_size] [-c source_dir] [-d debug_level] image_file看到这个输出就说明工具基本能跑。接下来你要重点确认的是默认值。有些版本在 help 里会标注默认块大小是 4096页大小是 256分区大小是 0x100000。不要以为默认值一定适合你的 ESP32后面我会详细讲怎么把这些参数和分区表对上。如果你的命令运行后没有任何输出也没有报错回到 3.2 检查 DLL如果提示“不是有效的 Win32 应用程序”八成是下载不完整或者被杀毒软件改坏了重新解压再试。窗口闪退的问题通常也是 DLL 缺失导致在 cmd 里运行会保留错误信息不要用双击的方式。4. 把目录封装成 LittleFS 镜像命令、参数和脚本整合工具能跑之后最核心的部分就是把一个普通目录变成可烧录的 littlefs.bin。这一章先给一个最简命令再逐项拆解参数最后放到自动构建脚本里让每次编译都自动生成镜像。4.1 最简用法一条命令生成 4MB 分区下的 data.bin假设你的项目目录结构是data/ index.html config.json certs/server.crt在项目根目录下执行mklittlefs.exe -c data -s 0x400000 -b 4096 -p 256 -d 0 data.bin这条命令会读取data目录下的所有文件和子目录生成一个 4MB0x400000 4MB的 LittleFS 镜像文件data.bin。注意-c data指封装 data 目录的内容而不是把 data 这个名字本身作为根目录。为什么块大小和页大小要写 4096 和 256这是 ESP32 Flash 最常见的擦除块和页大小配置。ESP-IDF 里挂载 LittleFS 时驱动默认也是按这个组合来初始化如果镜像里的配置和驱动侧不一致设备上会挂载失败。-d 0是关闭调试输出让命令保持安静方便在脚本里判断是否成功。生成完成后可以用一个十六进制查看器打开data.bin你会看到文件开头并不是data/的内容而是一段 LittleFS 的元数据结构和目录根。这个阶段的验证很有价值如果文件开头是一大堆零那很可能命令没执行成功或者输出文件路径写错了。4.2 参数逐一拆解-c、-s、-b、-p、-d 各管什么下面这个表是实战中最常用的几个参数建议把它截图保存。参数含义常用值说明-c指定要被封装进镜像的源目录data或build/webroot只封装目录内容不会把目录本身作为根节点-s镜像总大小0x1000001MB、0x4000004MB必须和设备分区表里的 data 分区大小一致-bFlash 块大小4096ESP32 的 SPI Flash 擦除块基本是 4096-pFlash 页大小256ESP32 内部 Flash 页大小标准是 256-d调试输出级别0、1、2排错时可以用1或2看详细日志-h帮助无不生成镜像只输出参数说明-s是最容易翻车的参数后面避坑章会专门讲。它代表的是整个文件系统分区的大小而不是你要放进去的文件总大小。如果你的源目录有 3MB 文件却只给了 1MB 的分区大小mklittlefs 会直接报错。反过来如果你给了 4MB 但实际分区表里只有 2MB设备挂载时会因为分区边界越界而找不到文件系统。-b和-p尽量不要随意改。除非你对 ESP32 Flash 硬件规格做过确认否则就用 4096 和 256 这两个值。有些 SMD 小容量 Flash 的块大小可能是 4096但页大小仍为 256所以组合基本固定。还有一个容易被忽略的点-c指定源目录时会把目录里的隐藏文件也封装进去。比如 Windows 资源管理器经常生成desktop.ini如果你在打包前不清理这些垃圾文件也会进镜像。后面脚本里我会给你一个清理步骤。4.3 在自动构建脚本里调用 mklittlefs一个通用模板手动敲命令不适合日常开发我一般把镜像生成整合进构建流程。下面是一个 Python 脚本模板放在项目根目录的build_image.py里import os import shutil import subprocess MKFS rC:\tools\mklittlefs\mklittlefs.exe SRC_DIR build/webroot OUT_BIN build/webroot.bin PARTITION_SIZE 0x400000 # 每次构建前清空旧目录避免删除的文件还残留在镜像中 if os.path.exists(SRC_DIR): shutil.rmtree(SRC_DIR) shutil.copytree(webroot, SRC_DIR) # 移除 Windows 系统产生的多余文件 for root, dirs, files in os.walk(SRC_DIR): for f in files: if f desktop.ini or f Thumbs.db: os.remove(os.path.join(root, f)) # 调用 mklittlefs 生成镜像 subprocess.run( [ MKFS, -c, SRC_DIR, -s, PARTITION_SIZE, -b, 4096, -p, 256, -d, 0, OUT_BIN, ], checkTrue, ) print(LittleFS image generated:, OUT_BIN)使用checkTrue的目的是让 Python 在 mklittlefs 返回非零退出码时直接抛异常构建流程停止避免拿着旧镜像去继续烧录。这个细节很重要否则命令失败但脚本照常往下走最后烧进去的是上一次的产物。参数集中放在脚本顶部方便根据实际分区大小修改。如果你的 web 前端来自前端构建工具可以在调用前用node或webpack把产物输出到webroot再执行这个 Python 脚本整个链路就变成一整套自动构建。5. 避坑Windows 下跑 mklittlefs 的 5 个高频翻车现场工具本身逻辑不复杂但 Windows 环境加上 ESP32 烧录流程组合起来翻车点非常多。这里写五个我亲身踩过或帮别人排查过的坑每条按现象、原因、解决来记录。5.1 双击没反应且没有报错现象双击 mklittlefs.exe 后没有任何窗口任务管理器里闪一下就消失。原因这是一个命令行程序不是 GUI 程序双击启动后没有终端窗口可以输出。更常见的是依赖 DLL 缺失但错误弹窗在闪退过程中来不及显示。解决不要在文件管理器里双击打开 cmd 或 PowerShell切到 exe 所在目录后运行.\mklittlefs.exe -h。如果命令行里能看到具体的 DLL 缺失提示按 3.2 的方式补 DLL。从那以后我拿到任何命令行工具都不会再双击了一律在终端里运行。5.2 运行提示“不是有效的 Win32 应用程序”现象在 64 位 Windows 上运行 exe系统提示“不是有效的 Win32 应用程序”。原因最常见的是下载不完整导致 PE 头损坏或者被杀毒软件隔离后留下的残留文件。还有一种情况是你实际运行的是一个 Linux ELF 文件而不是 Windows PE 文件——这种命名相似的包很容易在下载时选错。解决先看文件大小正常 i686 的 mklittlefs.exe 应该在 50KB 到 300KB 之间如果只有几 KB重新下载。再到压缩包属性里确认是来自 Windows 构建目标。如果杀毒软件隔离过恢复后先对 exe 右键属性看“数字签名”标签没有签名不代表一定有问题但要确认来源可靠。5.3 生成的 bin 烧进 ESP32 后无法挂载现象镜像明明生成成功烧录也成功但 ESP32 启动后 LittleFS 挂载返回ESP_FAIL或找不到文件系统。原因-s指定的镜像大小与分区表里 data 分区实际大小不一致。比如分区表里 data 分区是 1MB你却生成了 4MB 的镜像烧录后设备读取到超出分区的地址自然挂不上。另一个原因是-b、-p参数与 ESP-IDF 驱动初始化时使用的参数不匹配。解决用parttool.py -p COM3 show_partition_table查看 data 分区的偏移和长度核对-s的值。我常用的组合是-s 0x400000 -b 4096 -p 256但前提是分区表确实给了 4MB 空间。如果设备端想快速恢复可以在挂载失败回调里调用esp_littlefs_format重新格式化但这会清空预置文件只适合开发调试不宜在正式产品里直接启用。5.4 中文文件名在设备上变乱码现象源目录里明明有README-说明.txt烧录后在设备端看到的是乱码无法正常打开。原因Windows 下文件系统默认使用 GBK/GB2312 存储文件名而 LittleFS 内部按 UTF-8 编码。mklittlefs 打包时不会自动转码原样把文件名写入镜像。解决在生成镜像前把源目录里的非 ASCII 文件名统一改成 UTF-8 编码。最简单的方法是写一个 Python 脚本用os.rename把 GBK 文件名先转成 Unicode或用 ASCII 命名代替中文。我在项目规范里直接规定所有进入镜像的文件名必须使用[a-zA-Z0-9_-]字符从源头避开编码问题。如果你确实需要中文名那就得确保开发环境是 UTF-8 代码页并且构建机上的文件名已经是标准 UTF-8。5.5 镜像生成正常但烧录后文件全部变成 0 字节现象设备端能看到目录结构但打开每个文件大小都是 0内容为空。原因这个坑不在 mklittlefs而在烧录地址。镜像内容被写入到了错误的 Flash 偏移位置设备端挂载到了错误的地址读出的文件数据自然对不上。常见的是把镜像烧到了分区表里的偏移 0 或者主固件的地址。解决烧录前一定要确认地址。在 partitions.csv 里找到 data 分区的 offset通常在0x210000、0x310000这类位置。使用 esptool 烧录时要显式传递这个地址比如esptool.py --chip esp32 --port COM3 write_flash 0x210000 data.bin不要用0x00000或0x10000那种地址通常是 bootloader 或 app 分区。一个更稳妥的办法是用 ESP-IDF 的 Flash 下载工具它会依据分区表自动选择地址避免手动出错。6. 把镜像烧进 ESP32 并验证文件系统一个有效姿势工具链全部跑通后最后一件事就是烧录和验证。这里分享一个我在项目里一直用有效姿势生成镜像前记录源目录文件的哈希烧录后从设备端原样读回文件计算哈希做对比。这个方法能同时验证镜像是否正确、烧录地址是否对、文件内容有没有在传输中损坏。先用 Python 脚本给源目录生成一份哈希清单import hashlib import json import os ROOT data manifest {} for root, dirs, files in os.walk(ROOT): for f in files: path os.path.join(root, f) rel os.path.relpath(path, ROOT).replace(\\, /) with open(path, rb) as fh: manifest[rel] hashlib.sha256(fh.read()).hexdigest() with open(manifest.json, w) as fh: json.dump(manifest, fh, indent2)烧录后在 ESP32 端用一个简单的验证函数读取文件计算 SHA256 后通过串口打印。这里有一个小技巧每次构建前把manifest.json也放进 data 目录设备端读取完文件后自动和这份清单里的哈希比对不一致就置一个错误标志位这样即使串口日志刷屏也能知道哪个文件出了问题。在设备端遍历目录时我一般直接用 ESP-IDF 的 VFS 接口esp_vfs_littlefs_conf_t conf { .base_path /data, .partition_label storage, .format_if_mount_failed false, }; esp_vfs_littlefs_register(conf); DIR *d opendir(/data); struct dirent *e; while ((e readdir(d)) ! NULL) { printf(%s\n, e-d_name); } closedir(d);这段代码的重点是format_if_mount_failed设为false这样挂载失败会直接抛错方便我发现问题。如果设为true设备会悄悄重新格式化分区预置文件全部消失而你还以为没问题。这个验证流程帮我抓过无数次问题。有一次源目录里残留了一个.DS_Store它也被封装进了镜像虽然不影响主程序但串口列出文件时多了一个莫名其妙的名字后来我就在构建脚本里加了过滤规则。还有一次分区大小差了 4KB明明能列出文件但读取时偏移越界哈希对比直接暴露问题。从那以后我每次生成镜像之后都强制走一遍“本地 hash → 烧录 → 设备端读回 → 对比”的流程不再凭“能看见目录”就觉得万事大吉。希望帮到你。本文还有配套的精品资源点击获取