Working with filesystems 使用文件系统 ========================

This tutorial describes how MicroPython provides an on-device filesystem, allowing standard Python file I/O methods to be used with persistent storage. 本教程描述了MicroPython如何提供设备上的文件系统, 允许使用标准的Python文件I/O方法进行持久存储。

MicroPython automatically creates a default configuration and auto-detects the primary filesystem, so this tutorial will be mostly useful if you want to modify the partitioning, filesystem type, or use custom block devices. MicroPython自动创建默认配置并自动检测 主文件系统,所以如果您想修改,本教程将非常有用 分区、文件系统类型或使用自定义块设备。

The filesystem is typically backed by internal flash memory on the device, but can also use external flash, RAM, or a custom block device. 文件系统通常由设备上的内部闪存支持,但是 也可以使用外部闪存、RAM或自定义块设备。

On some ports (e.g. STM32), the filesystem may also be available over USB MSC to a host PC. pyboard_py also provides a way for the host PC to access to the filesystem on all ports. 在一些端口(例如STM32)上,文件系统也可以通过USB MSC访问 主机电脑。:ref:`pyboard_py`还为主机PC提供了访问的方法 所有端口上的文件系统。

Note: This is mainly for use on bare-metal ports like STM32 and ESP32. On ports with an operating system (e.g. the Unix port) the filesystem is provided by the host OS. 注意:这主要用于裸机端口,如STM32和ESP32。在港口 对于操作系统(例如Unix端口),文件系统由 主机操作系统。

VFS

MicroPython implements a Unix-like Virtual File System (VFS) layer. All mounted filesystems are combined into a single virtual filesystem, starting at the root /. Filesystems are mounted into directories in this structure, and at startup the working directory is changed to where the primary filesystem is mounted. MicroPython实现了一个类unix的虚拟文件系统(VFS)层。所有的安装 文件系统被组合到单个虚拟文件系统中,从根文件系统开始 /。文件系统被挂载到这个结构中的目录中 工作目录被更改为主文件系统所在的位置 安装。

On STM32 / Pyboard, the internal flash is mounted at /flash, and optionally the SDCard at /sd. On ESP8266/ESP32, the primary filesystem is mounted at /. On the OpenMV Cam the internal flash is mounted at / unless an SDCard is installed which will be moutned at / instead. 在STM32 / Pyboard上,内部flash被安装在``/flash``上,而且是可选的 在``/sd``处的SDCard。在ESP8266/ESP32上,主文件系统挂载在 /。在OpenMV Cam内部闪存安装在``/,除非SDCard 已安装,将改为在/``处安装。

Block devices 块设备 ————-

A block device is an instance of a class that implements the uos.AbstractBlockDev protocol. 块设备是实现类的实例 :类:`uos.AbstractBlockDev`协议。

Built-in block devices 内置的块设备 ~~~~~~~~~~~~~~~~~~~~~~

Ports provide built-in block devices to access their primary flash. 端口提供了内置的块设备来访问它们的主闪存。

On power-on, MicroPython will attempt to detect the filesystem on the default flash and configure and mount it automatically. If no filesystem is found, MicroPython will attempt to create a FAT filesystem spanning the entire flash. 在启动时,MicroPython将尝试检测默认的文件系统 自动闪存和配置并挂载它。如果没有找到文件系统, MicroPython将尝试创建横跨整个闪存的FAT文件系统。 Ports can also provide a mechanism to “factory reset” the primary flash, usually by some combination of button presses at power on. 通常,端口也可以提供一种机制来“工厂重置”主闪存 通过一些按钮的组合按下电源。

STM32 / Pyboard / OpenMV Cam

The pyb.Flash class provides access to the internal flash. On some boards which have larger external flash (e.g. Pyboard D), it will use that instead. The start kwarg should always be specified, i.e. pyb.Flash <pyb.Flash>`类提供了对内部Flash的访问。在一些 对于外接闪光较大的电路板(如Pyboard D),它将使用外接闪光 代替。应该始终指定``start` kwarg,即。 pyb.Flash(start=0).

Note: For backwards compatibility, when constructed with no arguments (i.e. pyb.Flash()), it only implements the simple block interface and reflects the virtual device presented to USB MSC (i.e. it includes a virtual partition table at the start). 注意:为了向后兼容性,当构造时不带参数(例如。 pyb.Flash()),它只实现简单的块接口并反映 提供给USB MSC的虚拟设备(例如,它包括一个虚拟分区表 开始时)。

ESP8266

The internal flash is exposed as a block device object which is created in the flashbdev module on start up. This object is by default added as a global variable so it can usually be accessed simply as bdev. This implements the extended interface. 中创建的块设备对象公开内部flash ``flashbdev``模块启动。默认情况下,此对象作为全局变量添加 变量,因此通常可以简单地作为``bdev``访问。这实现了 扩展接口。

ESP32

The esp32.Partition class implements a block device for partitions defined for the board. Like ESP8266, there is a global variable bdev which points to the default partition. This implements the extended interface. :类:class:`esp32.Partition`类实现分区的块设备 为董事会定义。像ESP8266,有一个全局变量``bdev``which 指向默认分区。这实现了扩展接口。

Custom block devices 自定义的块设备 ~~~~~~~~~~~~~~~~~~~~

The following class implements a simple block device that stores its data in RAM using a bytearray:: 下面的类实现了一个简单的块设备,用于存储其数据 使用``bytearray``:

class RAMBlockDev:
    def __init__(self, block_size, num_blocks):
        self.block_size = block_size
        self.data = bytearray(block_size * num_blocks)

    def readblocks(self, block_num, buf):
        for i in range(len(buf)):
            buf[i] = self.data[block_num * self.block_size + i]

    def writeblocks(self, block_num, buf):
        for i in range(len(buf)):
            self.data[block_num * self.block_size + i] = buf[i]

    def ioctl(self, op, arg):
        if op == 4: # get number of blocks
            return len(self.data) // self.block_size
        if op == 5: # get block size
            return self.block_size

It can be used as follows:: 它的使用方法如下:

import os

bdev = RAMBlockDev(512, 50) os.VfsFat.mkfs(bdev) os.mount(bdev, ‘/ramdisk’)

An example of a block device that supports both the simple and extended interface (i.e. both signatures and behaviours of the uos.AbstractBlockDev.readblocks() and uos.AbstractBlockDev.writeblocks() methods) is:: 同时支持简单和扩展的块设备的一个例子 接口(即,签名和行为 uos.AbstractBlockDev.readblocks()uos.AbstractBlockDev.writeblocks() methods) 是:

class RAMBlockDev:
    def __init__(self, block_size, num_blocks):
        self.block_size = block_size
        self.data = bytearray(block_size * num_blocks)

    def readblocks(self, block_num, buf, offset=0):
        addr = block_num * self.block_size + offset
        for i in range(len(buf)):
            buf[i] = self.data[addr + i]

    def writeblocks(self, block_num, buf, offset=None):
        if offset is None:
            # do erase, then write
            for i in range(len(buf) // self.block_size):
                self.ioctl(6, block_num + i)
            offset = 0
        addr = block_num * self.block_size + offset
        for i in range(len(buf)):
            self.data[addr + i] = buf[i]

    def ioctl(self, op, arg):
        if op == 4: # block count
            return len(self.data) // self.block_size
        if op == 5: # block size
            return self.block_size
        if op == 6: # block erase
            return 0

As it supports the extended interface, it can be used with littlefs 由于它支持扩展接口,因此可以使用:类:`littlefs:

import os

bdev = RAMBlockDev(512, 50)
os.VfsLfs2.mkfs(bdev)
os.mount(bdev, '/ramdisk')

Once mounted, the filesystem (regardless of its type) can be used as it normally would be used from Python code, for example:: 一旦挂载,文件系统(无论其类型)就可以作为文件系统使用 通常会从Python代码中使用,例如:

with open('/ramdisk/hello.txt', 'w') as f:
    f.write('Hello world')
print(open('/ramdisk/hello.txt').read())

Filesystems 文件系统 ———–

MicroPython ports can provide implementations of FAT, littlefs v1 and littlefs v2. MicroPython端口可以提供以下实现:class:FAT:类:`littlefs v1 <uos.VfsLfs1>` and littlefs v2

The following table shows which filesystems are included in the firmware by default for given port/board combinations, however they can be optionally enabled in a custom firmware build. 下表显示固件中包含哪些文件系统 默认为给定的端口/板组合,但他们可以选择 在自定义固件构建中启用。

Board

FAT

littlefs v1

littlefs v2

pyboard 1.0, 1.1, D

Yes

No

Yes

Other STM32

Yes

No

No

ESP8266

Yes

No

No

ESP32

Yes

No

Yes

FAT

The main advantage of the FAT filesystem is that it can be accessed over USB MSC on supported boards (e.g. STM32) without any additional drivers required on the host PC. FAT文件系统的主要优点是可以通过USB MSC访问它 在支持的板(例如STM32)上没有任何额外的驱动程序 主机电脑。

However, FAT is not tolerant to power failure during writes and this can lead to filesystem corruption. For applications that do not require USB MSC, it is recommended to use littlefs instead. 但是,FAT不能容忍写入过程中的电源故障,这可能导致 文件系统腐败。对于不需要USB MSC的应用程序,它是 建议改用littlefs。

To format the entire flash using FAT:: 使用脂肪来格式化整个flash:

# ESP8266 and ESP32
import os
os.umount('/')
os.VfsFat.mkfs(bdev)
os.mount(bdev, '/')

# STM32
import os, pyb
os.umount('/flash')
os.VfsFat.mkfs(pyb.Flash(start=0))
os.mount(pyb.Flash(start=0), '/flash')
os.chdir('/flash')

Littlefs

Littlefs is a filesystem designed for flash-based devices, and is much more resistant to filesystem corruption. Littlefs_是为基于闪存的设备设计的文件系统,它的功能远不止于此 防止文件系统损坏。

注解

There are reports of littlefs v1 and v2 failing in certain situations, for details see littlefs issue 347 and littlefs issue 295.

注意

有关于littlefs v1和v2失败的报告 有关详细信息,请参见 littlefs issue 347 and littlefs issue 295.

Note: It can be still be accessed over USB MSC using the littlefs FUSE driver. Note that you must use the -b=4096 option to override the block size. 注意:它仍然可以通过使用`littlefs FUSE driver`_.的USB MSC访问。注意,必须使用``-b=4096``选项来覆盖块 大小。

To format the entire flash using littlefs v2:: 使用littlefs v2格式化整个flash:

# ESP8266 and ESP32
import os
os.umount('/')
os.VfsLfs2.mkfs(bdev)
os.mount(bdev, '/')

# STM32
import os, pyb
os.umount('/flash')
os.VfsLfs2.mkfs(pyb.Flash(start=0))
os.mount(pyb.Flash(start=0), '/flash')
os.chdir('/flash')

Hybrid (STM32)

By using the start and len kwargs to pyb.Flash, you can create block devices spanning a subset of the flash device. 通过使用``start`` 和 len kwargs:class:pyb.Flash,你可以创建 跨越闪存设备子集的设备块。

For example, to configure the first 256kiB as FAT (and available over USB MSC), and the remainder as littlefs:: 例如,要将第一个256kiB配置为FAT(在USB MSC上可用), 剩下的就成了littlefs:

import os, pyb
os.umount('/flash')
p1 = pyb.Flash(start=0, len=256*1024)
p2 = pyb.Flash(start=256*1024)
os.VfsFat.mkfs(p1)
os.VfsLfs2.mkfs(p2)
os.mount(p1, '/flash')
os.mount(p2, '/data')
os.chdir('/flash')

This might be useful to make your Python files, configuration and other rarely-modified content available over USB MSC, but allowing for frequently changing application data to reside on littlefs with better resilience to power failure, etc. 这可能是有用的,使您的Python文件,配置和其他 很少修改的内容可通过USB MSC,但允许频繁 更改应用程序数据,使其驻留在littlefs上,具有更好的power弹性 失败,等等。

The partition at offset 0 will be mounted automatically (and the filesystem type automatically detected), but you can add:: 位于偏移位置``0``的分区将自动挂载(以及文件系统) 类型自动检测),但您可以添加:

import os, pyb
p2 = pyb.Flash(start=256*1024)
os.mount(p2, '/data')

to boot.py to mount the data partition. ``boot.py``来挂载数据分区。

Hybrid (ESP32)

On ESP32, if you build custom firmware, you can modify partitions.csv to define an arbitrary partition layout. 在ESP32上,如果您构建自定义固件,您可以修改``partitions.csv`` 定义任意分区布局。

At boot, the partition named “vfs” will be mounted at / by default, but any additional partitions can be mounted in your boot.py using:: 在引导时,名为“vfs”的分区默认挂载在``/``位置,但挂载为any 可以在引导中安装其他``boot.py``使用:

import esp32, os
p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')
os.mount(p, '/foo')