使用文件系统 内容 使用文件系统 6 B! m" Q$ x0 j
虚拟FS 块设备
& s h T3 N. Y8 K4 N& P. E% |" W内置块设备 ) \' P* d2 q4 y% {
自定义块设备
. \: C; e& o M, e4 p$ @ [
文件系统 C+ ~4 z4 N* |! ~
0 T9 k; [% K& d2 r9 t ) ^* L. P' @/ K- d' V; x" z
, g& o; b7 X4 X
本教程介绍 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 上,主文件系统挂载在 /。
7 D. o7 o- l# U. G% e" M T* e9 W! d块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。 - e# Y# E- g! E. D$ d
ESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。 1 X. D/ P$ K3 z/ R3 T' w+ W
ESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。
& ~3 x4 W8 [0 Y5 Q+ ~4 g# g# B1 J3 Z5 @2 s* J
自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:; ?7 F, R% t4 u- x" G* H$ _
- def __init__(self, block_size, num_blocks):# M6 n- s5 O4 W) J
- self.block_size = block_size' ^9 X% P% _: z: L
- self.data = bytearray(block_size * num_blocks)- o3 q: O3 \. h3 A8 z
- % @5 ~8 g+ D( ?8 d1 [1 s7 f
- def readblocks(self, block_num, buf):" y5 d% U) {' B) g/ T F& O
- for i in range(len(buf)):
# T& _' d7 M e/ J+ |. X$ v N - buf[i] = self.data[block_num * self.block_size + i]
3 h o! Y1 j T. v0 p, ?
1 Z: \9 `! H d% m- def writeblocks(self, block_num, buf):( a& m% X7 z, Y$ P6 C: z& g- N
- for i in range(len(buf)):. C: i+ Z+ k0 Y" A3 }5 b% O
- self.data[block_num * self.block_size + i] = buf[i]3 [0 L7 o* y% e, f# }3 Y" W! o5 s% ~
- f2 T( `" y) w2 [/ a, U/ ^. s! e
- def ioctl(self, op, arg):+ x; }: _. k& h' e
- if op == 4: # get number of blocks
/ q" Z* R6 J$ r4 H4 o% c - return len(self.data) // self.block_size
2 w$ D+ {( ?& k; s( a9 E P - if op == 5: # get block size8 k. r1 g4 c" w% ~
- return self.block_size
复制代码
, N3 B7 Z7 M! s# e, n& V( Z8 S3 o% A I
) z A6 |+ v4 a b: G
它可以按如下方式使用: - import os
& r Z. ^) g1 _; }3 ` - 3 [2 n4 D& K8 n8 Q8 K% b3 z
- bdev = RAMBlockDev(512, 50)# n$ f* X* ]6 g2 F
- os.VfsFat.mkfs(bdev)+ l, Y; `, S4 u2 l1 L" P+ h" Y3 b
- os.mount(bdev, '/ramdisk')
复制代码 5 @+ b4 U. c0 q2 b3 z9 }
4 o" f, o# t2 |% f O) }
: e2 k. k5 l' Y6 a支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:0 y# i- P) ` I4 E& b0 _4 a. e
- def __init__(self, block_size, num_blocks):
- B* ^) t( q" M; h6 `( J& [ - self.block_size = block_size
0 Y' |8 x5 F$ S; V- f - self.data = bytearray(block_size * num_blocks)% O$ V) K$ e/ k8 [% M; d
- 5 Z" I$ W# t- h z9 {
- def readblocks(self, block_num, buf, offset=0):
7 s. ~( V, L. q, H - addr = block_num * self.block_size + offset
; z8 Z0 U7 c N7 H/ [ - for i in range(len(buf)):
+ |( x+ m& G6 Y T* _0 T - buf[i] = self.data[addr + i]3 \' d) d/ ?2 Z" _4 x0 s. o( s
- . ]4 i- K7 i, ]3 `; f
- def writeblocks(self, block_num, buf, offset=None):
3 `5 x$ ~ E* a6 M - if offset is None:
: [9 O1 U7 z* _9 ` - # do erase, then write
! f; I1 K; A) a3 n - for i in range(len(buf) // self.block_size):
# M& P( t$ A: J& M; y4 n& j3 C+ f# M - self.ioctl(6, block_num + i)
- ^, j2 t) d4 k6 F! ~8 G- l - offset = 0
" g# P- j$ }1 | - addr = block_num * self.block_size + offset* s) c1 L/ q0 E$ p! X& b
- for i in range(len(buf)):
I) e- k/ F+ A* ?8 R. M+ \ - self.data[addr + i] = buf[i]# f* p, A8 V9 J' p8 Q0 |; q% D
- 9 P* E' s/ v" N9 f! X0 O0 k7 H
- def ioctl(self, op, arg):
6 o0 L( }3 j$ X. A9 O - if op == 4: # block count
1 ]9 y- M7 w0 u! _8 {, o4 \& B+ f - return len(self.data) // self.block_size
: P7 S% G( V9 ]0 T+ { - if op == 5: # block size
1 C( z- K1 O3 t, l - return self.block_size
6 @) T4 A0 Y8 |' J$ u/ g8 Y - if op == 6: # block erase! i6 f/ Q8 m+ O3 F' b
- return 0
复制代码 * H5 A) w' {# A) M
" f; t: [* X4 _* Z6 O Y5 A7 r
( S9 O+ e7 I/ R9 O
由于它支持扩展接口,因此可以用于littlefs: - import os
9 y" q7 Q% B+ j# ^" N9 t, D) P - 2 |6 ]& @; T! }, @
- bdev = RAMBlockDev(512, 50)9 e- N) ]6 l1 S, j2 j( x
- os.VfsLfs2.mkfs(bdev)
6 D- w. V' K" U' U - os.mount(bdev, '/ramdisk')
复制代码
9 i; ~0 X, x% n5 S9 r6 L" o1 v3 r1 L7 A% \
6 ]$ s) t5 W* r$ e$ ]& |
一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:! V! H# p/ M+ Q' x7 r
- f.write('Hello world')
/ D) ]0 H6 O! K" c5 ?. U! z - print(open('/ramdisk/hello.txt').read())
复制代码 , x+ r. {5 S% V
- n$ j& s2 M' r, ^6 N/ G% @( ^( M2 z: Z) v# y
$ M, i1 o0 L( W5 W1 Z% z3 ?5 l
! Z: U; S0 ~" w- P, E% u& ~/ R文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。 ' k4 w! l' l# u& [& r$ Z! `; t, m
FATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP32
7 q' k4 n: x9 S1 J& H - import os
5 [$ Z) r3 i3 N- | - os.umount('/')) Q9 l& b5 |0 Z; W+ I* ?) `. u2 M- j
- os.VfsFat.mkfs(bdev)8 k+ g7 Q7 p3 J4 z& @
- os.mount(bdev, '/')! C) y: ~& |! K
. p, }9 ^% u/ _1 l& L0 d/ J6 r- # STM32
) ?" R, H5 l0 M, \+ v3 l8 W, ] - import os, pyb
S. e# u2 o. C! E# X - os.umount('/flash')" u9 x! s9 g8 |3 j, y
- os.VfsFat.mkfs(pyb.Flash(start=0))
& j1 z3 d7 a, [! J2 Q( W - os.mount(pyb.Flash(start=0), '/flash')
, a6 C9 \6 C3 v# X# Q7 B - os.chdir('/flash')
复制代码 5 D" g' k3 \( P3 d v
" }; Q- c& u N/ I' @
) f p+ B% q0 p z" L7 ]. `/ ?+ T
7 r5 ^# c- c) {LittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295. / u/ Q4 M6 P9 J8 Z/ U' _+ {) C
注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP320 {& l0 [3 P9 t' _4 i* C8 K2 w
- import os A: q& |8 Q' z7 n5 d. V |/ p
- os.umount('/')
7 B) ~6 d2 O! M - os.VfsLfs2.mkfs(bdev)$ ~, C. G9 @" p6 \ R
- os.mount(bdev, '/')
( W9 ~$ {" b) y+ t( e$ q8 |
$ b( M% a0 ^ Q9 n& M- # STM320 e0 V T; B9 }
- import os, pyb3 q+ z, I# T2 U) a% |9 H! i
- os.umount('/flash'): O E5 K1 b/ v. E! P" L
- os.VfsLfs2.mkfs(pyb.Flash(start=0))& k( e" v3 h+ L5 Y
- os.mount(pyb.Flash(start=0), '/flash'); {; G @. u* ^' H9 x: ]
- os.chdir('/flash')
复制代码 7 I* U2 w! N) r2 R0 T; b& C
* i- ]( N1 f* \6 S5 q$ N
- ^- c& s& t5 s- j8 }+ Q
7 s) k* c' T! J混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb2 ?. c1 f- j2 X6 J! O! e" i
- os.umount('/flash')
# ~4 n5 W. U; K - p1 = pyb.Flash(start=0, len=256*1024)' b$ q, m- `- h5 q
- p2 = pyb.Flash(start=256*1024)
& c6 z( e- _# n( b& p8 s - os.VfsFat.mkfs(p1)4 @0 L- o6 [8 `3 }' Q3 x5 n+ ?
- os.VfsLfs2.mkfs(p2)7 u; A5 |& G: [
- os.mount(p1, '/flash') L; {& j( X, Z* U1 k
- os.mount(p2, '/data')
- d8 C( \: ?* C) S+ v, ^ w' Q - os.chdir('/flash')
复制代码 ( z( f W3 @/ F' E r* o
7 [$ y# J6 U7 g8 N! d; u2 H
9 g$ F( d( U0 v0 M2 n3 t' E
这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb7 H$ v! _- D n" u5 P4 P0 k
- p2 = pyb.Flash(start=256*1024)
3 Z9 C0 g) u9 Q" S/ _ - os.mount(p2, '/data')
复制代码 2 b7 ~ U Y3 U
5 K6 d6 C/ v9 L, J) I! L
, d* W& n9 @# J& Q/ C5 e( J
来 boot.py挂载数据分区。
* r$ C( {! y( h: p' V+ ~+ F8 o混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os
' L( {( J- Q/ [2 h - p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')% H; J* X0 s) A' l
- os.mount(p, '/foo')
复制代码 - f- y# X" i( F7 }2 J0 Y
' Q6 z" T1 x$ ?4 |, `' t5 P
- ~/ A9 f0 y6 ^. `4 w
$ d2 ]( ]; \! A/ F+ K6 X- _& D( G4 e/ @& ]) r1 a1 j5 |) X$ n
/ L& B. s4 p$ |, ]( `
|