vfs --- 虚拟文件系统控制

vfs 模块包含用于创建文件系统对象并在虚拟文件系统中挂载/卸载它们的函数。

文件系统挂载

某些移植版提供了虚拟文件系统(VFS)以及在该 VFS 中挂载多个"真实"文件系统的能力。文件系统对象既可以挂载在 VFS 的根目录下,也可以挂载在位于根目录下的子目录中。这使得 Python 程序所看到的文件系统能够进行动态且灵活的配置。具备此功能的移植版会提供 mount()umount() 函数,以及可能由 VFS 类表示的各种文件系统实现。

vfs.mount(fsobj: Any, mount_point: str, *, readonly: bool = False) None

将文件系统对象 fsobj 挂载到由 mount_point 字符串指定的 VFS 位置。fsobj 可以是带有 mount() 方法的 VFS 对象,也可以是块设备。如果它是块设备,则会自动检测文件系统类型(如果未识别出任何文件系统,则会引发异常)。mount_point 可以是 '/' 以将 fsobj 挂载在根目录,或者是 '/<name>' 以将其挂载在根目录下的子目录。

如果 readonlyTrue,则以只读方式挂载文件系统。

在挂载过程中,会调用文件系统对象上的 mount() 方法。

如果 mount_point 已被挂载,则会引发 OSError(EPERM)

vfs.mount() List[Tuple[Any, str]]

在不向 mount() 传递任何参数的情况下,返回一个表示所有活动挂载点的元组列表。

返回的列表形式为 [(fsobj, mount_point), ...]

vfs.umount(mount_point: str | Any) None

卸载文件系统。mount_point 可以是指定挂载位置的字符串,也可以是先前已挂载的文件系统对象。在卸载过程中,会调用文件系统对象上的 umount() 方法。

如果未找到 mount_point,则会引发 OSError(EINVAL)

class vfs.VfsFat(block_dev: AbstractBlockDev)

创建一个使用 FAT 文件系统格式的文件系统对象。FAT 文件系统的存储由 block_dev 提供。由此构造函数创建的对象可使用 mount() 进行挂载。

static mkfs(block_dev: AbstractBlockDev) None

block_dev 上构建 FAT 文件系统。

class vfs.VfsRom(buffer: bytes | bytearray | memoryview)

创建一个使用 ROMFS 只读文件系统格式 的文件系统对象。buffer 必须是一个支持缓冲区协议(bytesbytearraymemoryview)且包含有效 ROMFS 映像的对象。

由此构造函数创建的对象可使用 mount() 进行挂载。

完整详情请参阅 使用 ROMFS,其中包括如何使用 mpremote 构建和部署 ROMFS 映像。

vfs.rom_ioctl(op: int, *args: Any) Any

用于访问设备只读存储器(ROM)分区的底层接口。支持的操作包括:

调用

行为

rom_ioctl(1)

返回可用 ROM 分区的数量。

rom_ioctl(2, id)

将分区 id 作为 memoryview 返回。

rom_ioctl(3, id, length)

擦除分区 id 的前 length 个字节以准备写入。返回以字节为单位的最小写入对齐值。

rom_ioctl(4, id, offset, buf)

buf 写入分区 id 的字节 offset 处。

rom_ioctl(5, id)

完成对分区 id 的写入序列(刷新缓存等)。

在部署 ROMFS 映像时,这些操作通常由 mpremote 间接调用;大多数应用程序无需直接调用它们。

class vfs.VfsPosix(root: str | None = None)

创建一个访问宿主 POSIX 文件系统的文件系统对象。如果指定了 root,则它应是宿主文件系统中用作 VfsPosix 对象根目录的路径。否则使用宿主文件系统的当前目录。

备注

VfsPosix 仅在 MicroPython Unix 移植版上可用;它不存在于 OpenMV Cam 固件中。

块设备

块设备是实现了块协议的对象。这使得设备能够支持 MicroPython 文件系统。物理硬件由用户定义的类表示。AbstractBlockDev 类是此类设计的模板:MicroPython 实际上并不提供该类,但实际的块设备类必须实现下文所述的方法。

此类的具体实现通常会允许访问某个硬件(如闪存)的类内存功能。块设备可以被格式化为任何受支持的文件系统,并使用 os 方法进行挂载。

块设备使用下文所述的块协议两种变体的示例实现请参阅 使用文件系统

简单接口与扩展接口

readblockswriteblocks 方法有两种兼容的签名(见下文),以支持多种使用场景。给定的块设备可以实现其中一种形式,或者同时实现两种形式。第二种形式(带有 offset 参数)被称为"扩展接口"。

某些文件系统需要对写入操作有更多的控制——例如,在不擦除的情况下写入子块区域——并且需要块设备支持扩展接口。

class vfs.AbstractBlockDev

块设备协议的文档模板。MicroPython 实际上并不暴露此类——此处展示它仅是为了说明用户定义的块设备类必须实现的方法。构造函数参数完全由实现决定(通常是闪存总线、片选引脚、扇区大小等)。

readblocks(block_num: int, buf: bytearray) None
readblocks(block_num: int, buf: bytearray, offset: int) None

从设备读取字节到 buf 中。两种重载分别暴露 简单接口与扩展接口

简单形式readblocks(block_num, buf)):从块索引 block_num 开始读取整块。len(buf) 必须是块大小的整数倍,读取的块数为 len(buf) // block_size

扩展形式readblocks(block_num, buf, offset)):从块 block_num 内的字节 offset 处开始读取 len(buf) 个字节——不一定是整数个块。当文件系统需要子块读取访问时使用此形式。

writeblocks(block_num: int, buf: bytes) None
writeblocks(block_num: int, buf: bytes, offset: int) None

将字节从 buf 写入设备。

简单形式writeblocks(block_num, buf)):从块索引 block_num 开始写入整块。len(buf) 必须是块大小的整数倍,写入的块数为 len(buf) // block_size。如果底层硬件需要,实现负责先擦除每个目标块。

扩展形式writeblocks(block_num, buf, offset)):从块 block_num 内的字节 offset 处开始写入 len(buf) 个字节——不一定是整数个块。只有正在写入的字节可能会改变;调用者负责确保受影响的块已通过先前的 ioctl(6, block_num) 调用被擦除。此形式的实现绝不能隐式擦除块,即使 offset 为零也是如此。

ioctl(op: int, arg: int) int | None

控制块设备并查询其参数。要执行的操作由 op 指定,它是以下整数之一:

  • 1 —— 初始化设备(arg 未使用)

  • 2 —— 关闭设备(arg 未使用)

  • 3 —— 同步设备(arg 未使用)

  • 4 —— 获取块数量的计数,应返回一个整数(arg 未使用)

  • 5 —— 获取一个块中的字节数,应返回一个整数,或返回 None(此时使用默认值 512)(arg 未使用)

  • 6 —— 擦除一个块,arg 为要擦除的块编号

至少必须拦截 ioctl(4, ...);使用扩展接口的文件系统还额外需要 ioctl(6, ...)。是否需要其他操作取决于硬件。

在任何对 writeblocks(block, ...) 的调用之前,使用扩展接口的文件系统都会发出 ioctl(6, block),以便驱动程序在硬件需要时先擦除该块。驱动程序也可以转而拦截 ioctl(6, block) 并返回 0(成功),从而自行承担检测何时需要擦除的责任。

除非另有说明,ioctl(op, arg) 可以返回 None。因此,实现可以忽略 op 的未使用值。对于被拦截的 op,操作 4 和 5 的返回值如上文所述。其他操作成功时应返回 0,失败时返回非零值,所返回的值为 OSError 的 errno 错误码。