使用文件系统 内容 使用文件系统
) a+ d* L) f: C% l9 J虚拟FS 块设备
6 H: {! ^6 e, a0 `( Y9 }内置块设备 ) l4 x3 O& o4 h! o( l6 c3 _
自定义块设备
% [- H1 D+ D# j/ N5 s
文件系统
. L" @1 T$ _7 W0 u- T+ x+ I e. _5 G$ N8 [9 U: B5 P
3 a4 Y, k9 v# M9 G0 Q! N , I5 {9 F, Q2 w' @ E! ^1 e6 z! J
本教程介绍 MicroPython 如何提供设备上的文件系统,允许将标准 Python 文件 I/O 方法与持久存储一起使用。 MicroPython 会自动创建默认配置并自动检测主文件系统,因此如果您想修改分区、文件系统类型或使用自定义块设备,本教程将非常有用。 文件系统通常由设备上的内部闪存支持,但也可以使用外部闪存、RAM 或自定义块设备。 在某些端口(例如 STM32)上,文件系统也可以通过 USB MSC 连接到主机 PC。pyboard.py 工具还为主机 PC 提供了一种访问所有端口上的文件系统的方法。 注意:这主要用于 STM32 和 ESP32 等裸机端口。在带有操作系统的端口(例如 Unix 端口)上,文件系统由主机操作系统提供。 虚拟FSMicroPython 实现了一个类 Unix 虚拟文件系统 (VFS) 层。所有挂载的文件系统都组合成一个单一的虚拟文件系统,从 root 开始 /。文件系统被挂载到这个结构的目录中,并且在启动时工作目录被更改为主文件系统被挂载的位置。 在 STM32/Pyboard 上,内部闪存安装在 /flash,可选的 SDCard安装在/sd。在 ESP8266/ESP32 上,主文件系统挂载在 /。
3 ?2 y0 d& h+ R' g. `. z) @/ |块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。 ! b* _4 ~) x: J0 v: S
ESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。 0 i: ~ Z" G% q* p3 }. e D" f
ESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。 ' q0 ?+ W0 W4 h; E
' n! k& ~* V" A: G
自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:
- T/ {0 X& v( s) c, j - def __init__(self, block_size, num_blocks):
$ Y2 j4 G) P+ B1 v3 k' |2 z - self.block_size = block_size% X/ v% i* d/ s& T, h& | i. u
- self.data = bytearray(block_size * num_blocks)1 h' G! h0 a: X8 p- |* A9 z
: z7 h \; G8 H. y6 o" W' u! w- def readblocks(self, block_num, buf):
8 T$ A) E; |3 y4 g - for i in range(len(buf)):: y" W) T9 K) d% Y" V
- buf[i] = self.data[block_num * self.block_size + i]% @. y8 D$ y, J% ]5 Q* ^/ O7 n6 \
- , j Y4 e3 c0 a- P1 M4 M
- def writeblocks(self, block_num, buf):
' B2 U7 E% W6 O# ]7 j' [. d. P - for i in range(len(buf)):
( g8 \3 e7 u) p1 ]8 b7 {" W - self.data[block_num * self.block_size + i] = buf[i]9 J g, v3 D7 `$ _
: A1 O5 _! E- T, y" M' k* C- def ioctl(self, op, arg):! n' C: L& C" ^& a
- if op == 4: # get number of blocks2 o7 ?5 h3 f: U8 N5 M5 {; p5 @1 g
- return len(self.data) // self.block_size
" d$ B4 r" W. v' I/ E" X: F - if op == 5: # get block size
# D6 @* K1 J1 }1 \$ I. K! x - return self.block_size
复制代码
9 C# L G$ e ?1 W9 u1 g: v) C/ W
! g" b( B- [ y它可以按如下方式使用: - import os
' A$ R; L) j8 n/ S# r. d8 W
; y2 a* ?- H5 K1 w2 X) b, x" F- bdev = RAMBlockDev(512, 50)
4 f6 {" z; E+ ~ y6 S - os.VfsFat.mkfs(bdev) S0 d; T7 j2 w; L% z
- os.mount(bdev, '/ramdisk')
复制代码 ' e+ V; Z0 K6 N& k2 H
* v4 z4 j+ S" L$ o! ^
, P0 t% H+ e4 A3 F. W0 }1 E- h6 C
支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:
4 ^# ]5 x& G3 [% D. v# \/ h" o/ W - def __init__(self, block_size, num_blocks):
- f. N! P B0 D8 g2 ] - self.block_size = block_size
M6 h% |& R5 c- X - self.data = bytearray(block_size * num_blocks)
* H3 u2 H, ?5 K, l& A! c K1 M- z - 7 f& |" y0 ` i$ Q) o
- def readblocks(self, block_num, buf, offset=0):: [7 E7 J: O S1 ^- A/ X- q8 D
- addr = block_num * self.block_size + offset
, {$ N2 [* b4 r% Z& F - for i in range(len(buf)):
' r2 r6 r. k& u( T" X - buf[i] = self.data[addr + i]
9 Z( f$ z \) P( L* v- |: e' \ - 1 L8 f% X' i) H3 R3 H( B
- def writeblocks(self, block_num, buf, offset=None):
1 ]! T" R) \( @0 u - if offset is None:$ q' I3 ~! r g
- # do erase, then write% ~9 j1 S' v4 m. l V
- for i in range(len(buf) // self.block_size):$ y, {8 ?) d3 G! Q
- self.ioctl(6, block_num + i)( o5 ?& i, l% {6 D0 B8 F( J
- offset = 0
, S& L" w+ \$ N) O - addr = block_num * self.block_size + offset
. M3 F$ b7 G" }8 z - for i in range(len(buf)):: b* f" q/ F" D: d+ Z; {
- self.data[addr + i] = buf[i]
3 l3 Q" m" y- m. E! S
. G! n0 ^' W' ?* y% U( G6 V6 e- def ioctl(self, op, arg):) V) C; ~+ _& w( R$ ?3 t
- if op == 4: # block count
: U$ E" e3 R1 P2 Q' i+ p - return len(self.data) // self.block_size$ Y5 s' b: N+ l$ B+ C0 c
- if op == 5: # block size
R" l3 b9 L, U - return self.block_size) p# y. W7 h4 l
- if op == 6: # block erase. p) m7 l/ g! F7 t
- return 0
复制代码 7 T8 t/ S5 e, b
. I/ T& i) f: r) {% J$ r0 ^
5 I8 C( r1 @6 A" L( \
由于它支持扩展接口,因此可以用于littlefs: - import os
% t" ?7 T1 S! x
: K- v5 S4 i9 r' b {- bdev = RAMBlockDev(512, 50)4 t+ O( u4 L8 X6 `- E
- os.VfsLfs2.mkfs(bdev)
; d" c2 L- Q) f q! C - os.mount(bdev, '/ramdisk')
复制代码 5 Y9 G }' ?' R
5 A7 c4 O" C% d: H/ ?# v8 ~) ?
3 V8 b4 V7 a7 P5 o' W6 Z
一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:
6 s" n+ J$ c. {- b O* M - f.write('Hello world')' F( O! V( N' @8 _: J4 M
- print(open('/ramdisk/hello.txt').read())
复制代码
# v' o' W8 \8 e5 ^$ I
, |' |! g! r. T2 g- x; y- S* M/ H' K, l# }* P" P) R) U' R6 k& A
5 j8 {& m! ]* s& y s
/ c, i$ t( y) \1 e) E+ y7 s5 n1 K' ^文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。 ' `2 d1 B0 ]- ?4 l1 e
FATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP32$ B" F, h6 ?& x- X1 t+ d# J
- import os) v' |, t7 W' D4 `9 A
- os.umount('/') k8 U! A! R% F$ U* |
- os.VfsFat.mkfs(bdev)( v0 F" X& L( j: o8 s3 N
- os.mount(bdev, '/')( Y+ Z' h: n# E( B9 k
- + L* T0 k$ o8 p1 f
- # STM32
) d" @$ i: ], Q2 c% i d - import os, pyb
9 p9 r% a( f a# r, t' w9 t - os.umount('/flash')6 V' h5 u# z% @' a
- os.VfsFat.mkfs(pyb.Flash(start=0))
) n, t* ?8 S; ?" y$ S0 j - os.mount(pyb.Flash(start=0), '/flash')
' k$ h: d, L& V, j& t! H - os.chdir('/flash')
复制代码
! J" J) m0 S8 k k, |" z$ a( a6 F1 J+ J! v/ `( Z) \
5 `" D2 V; v) z& F/ g( f* b* T! [8 F+ e e, r
LittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295. ! Z& Z7 n% t" }- _ l; _# ^$ J( r
注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP32
4 x7 l7 i- u, W0 z* [. ^ - import os: E" U0 W9 f, q6 _1 u( s9 H8 a0 e1 E
- os.umount('/')" e( ]) C/ s0 n6 R4 p: F! A, {
- os.VfsLfs2.mkfs(bdev) \6 K; ~4 i' ]" Z- l" G# W
- os.mount(bdev, '/')
/ ^0 @+ \# a6 r2 e - : A+ @8 B* ^0 ] [
- # STM32
( U* o2 c+ W' H6 I2 O - import os, pyb
& J- ?; B6 p4 Z9 b( k - os.umount('/flash')
8 C- K5 l6 w6 i/ V9 F; d - os.VfsLfs2.mkfs(pyb.Flash(start=0))$ h# ]' I) F& _6 h6 M: P' \# a1 M1 q
- os.mount(pyb.Flash(start=0), '/flash')
3 }( h/ B) |+ C! r+ N" c( C+ w - os.chdir('/flash')
复制代码
* i0 B6 G5 l1 o; }
) M: y" y* D' b1 _- Q9 U5 X; W" x( B7 N# T: Y
# X. s& R3 K/ K8 F; t! W9 L
混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb3 h" H: f( ^: J
- os.umount('/flash')
6 T1 f! a6 a/ H: g: q - p1 = pyb.Flash(start=0, len=256*1024)
* I# f; n' ~- ~- l7 ^, n e - p2 = pyb.Flash(start=256*1024)8 r8 Q* h$ _7 Q4 x, {
- os.VfsFat.mkfs(p1)3 ^, R: b. x/ @' R/ O& {
- os.VfsLfs2.mkfs(p2)0 u3 E3 q) h- a
- os.mount(p1, '/flash')9 D- i( g6 V$ i! f6 Z: }
- os.mount(p2, '/data')% q4 e6 I/ \7 g* Y" T) o' _) }8 W( D
- os.chdir('/flash')
复制代码
" W3 d. p6 l. t
; Q1 T4 t7 T2 j# K: W
2 K* J1 b( J' {. {这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb
0 T7 S. [$ b% ?7 Y3 }2 G3 h. M - p2 = pyb.Flash(start=256*1024)% i7 t6 `, V: C
- os.mount(p2, '/data')
复制代码
/ R$ h' D7 s |+ U4 y; C4 {( @
& o9 ?% I% t* r) M9 Y* v. N
: @" J& w) P& S; f w* S8 F$ a来 boot.py挂载数据分区。
& K2 g6 d" H7 y, Y! J混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os
: p9 V5 z6 S& e# K" v$ [ - p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')0 j$ }6 H% V) l/ P* ]: L
- os.mount(p, '/foo')
复制代码
2 W* J$ B( A8 F/ _( {. P: @- Z2 G: s% }5 u
4 L% J A, j# r( j5 S i# y7 M
' b7 U: e2 b# L4 U
& b9 X+ P" S: j& [' j4 L8 r/ _4 ?( q' _: m i7 Z M
|