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>'以将其挂载在根目录下的子目录。如果 readonly 为
True,则以只读方式挂载文件系统。在挂载过程中,会调用文件系统对象上的
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必须是一个支持缓冲区协议(bytes、bytearray或memoryview)且包含有效 ROMFS 映像的对象。由此构造函数创建的对象可使用
mount()进行挂载。
- 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 间接调用;大多数应用程序无需直接调用它们。
块设备¶
块设备是实现了块协议的对象。这使得设备能够支持 MicroPython 文件系统。物理硬件由用户定义的类表示。AbstractBlockDev 类是此类设计的模板:MicroPython 实际上并不提供该类,但实际的块设备类必须实现下文所述的方法。
此类的具体实现通常会允许访问某个硬件(如闪存)的类内存功能。块设备可以被格式化为任何受支持的文件系统,并使用 os 方法进行挂载。
块设备使用下文所述的块协议两种变体的示例实现请参阅 使用文件系统。
简单接口与扩展接口¶
readblocks 和 writeblocks 方法有两种兼容的签名(见下文),以支持多种使用场景。给定的块设备可以实现其中一种形式,或者同时实现两种形式。第二种形式(带有 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 错误码。