使用文件系统 内容 使用文件系统
2 m( }% S% U9 e6 P虚拟FS 块设备 7 _/ Z1 n; z& R% q0 t7 _9 a
内置块设备 3 t; B7 S' `' |+ M) e7 w
自定义块设备 & s1 o8 C+ B9 s2 O/ e
文件系统 , q: K0 D( R7 `7 G% ~% _4 U
; R0 y" v$ U7 t& C2 N% O% y! h
! p6 ^8 E& o1 a$ P* X3 z, `; ~2 k2 @- B
: A1 D# P" h1 k) [! d( V! 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 上,主文件系统挂载在 /。
; Y0 x; d' d, Y/ y3 Q& I% e块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。
4 x p$ m1 |4 H& Y4 C0 a3 rESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。 & V- h3 v }5 A. o% a" V
ESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。 4 X. o' g3 r7 Y1 z8 e
1 v) |: e2 q( h& V6 E, K9 [7 g
自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:
, P/ O2 `2 ?" T+ f, g" { - def __init__(self, block_size, num_blocks):2 f H w8 J3 B3 S1 e7 b8 u' N
- self.block_size = block_size1 w3 b! r9 B o2 a1 h
- self.data = bytearray(block_size * num_blocks)) B5 J; ]$ a% s
- " [, \/ O+ Y* N3 }! F
- def readblocks(self, block_num, buf):
9 Y- v( @$ r- l5 i7 ?9 U - for i in range(len(buf)):
6 D. R2 ^" B U+ S6 h& \ - buf[i] = self.data[block_num * self.block_size + i]
" @" q! H. E/ Y Z. ]9 X1 n: [) j
5 n# X3 j; g4 W7 x) W- def writeblocks(self, block_num, buf):
0 e* Y) a6 D2 M$ ?5 e& r$ ~ - for i in range(len(buf)):
/ e6 ]: F- w$ Z8 U/ F - self.data[block_num * self.block_size + i] = buf[i]
- T) I% H) @% v# J3 \8 s: O5 X1 e
. {2 L' M7 R$ a& d- def ioctl(self, op, arg):
* v! }- d2 i5 i; Y/ U8 I/ e - if op == 4: # get number of blocks7 A q9 D1 X- V" M# ~
- return len(self.data) // self.block_size
, \2 e0 C' C: q- N) P/ N5 Y - if op == 5: # get block size
" g: E+ J t" m! @+ w - return self.block_size
复制代码 : T' k5 m9 @/ `( X: G9 x! K9 @
9 ]3 b( f, Y' e2 X$ v/ h) B, A. w
" J# a( d3 P {9 A) }8 G它可以按如下方式使用: - import os
0 r8 T4 |8 Y6 K0 ?4 y% U - * M! {6 A% Z, ?6 ]2 E8 G4 t
- bdev = RAMBlockDev(512, 50): Q8 j4 Z7 H: O1 v
- os.VfsFat.mkfs(bdev)! S7 J! A: B" t3 o r- s
- os.mount(bdev, '/ramdisk')
复制代码 4 i9 V9 _5 H; Y: g
4 X, H6 |% r1 E( ?# m4 x
) q3 i7 k8 [+ c: x1 m2 ]" O3 X支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:0 ?# E4 g* B% @( y6 J
- def __init__(self, block_size, num_blocks):
/ \/ ^$ m, B# j* l7 Z - self.block_size = block_size3 j) L4 L$ B; W
- self.data = bytearray(block_size * num_blocks)5 ?+ @$ b% G6 Z( M8 R, G$ S$ W
1 x! T. A0 @+ E1 T$ r- def readblocks(self, block_num, buf, offset=0):
9 |' g3 O" z u" t4 Y" _ - addr = block_num * self.block_size + offset
' K6 M/ m U( G2 x+ W - for i in range(len(buf)):+ m/ F' c$ Y7 v2 c% k7 L( t1 }
- buf[i] = self.data[addr + i]: b7 z: w; n: m `7 N0 |" _
- $ K; ]- C5 O& O' s' I; {
- def writeblocks(self, block_num, buf, offset=None):: s% C7 r! p, z
- if offset is None:
" I) Z* }* B3 W; e - # do erase, then write
8 S+ p; ?% `2 Z: m9 k+ {" t" | - for i in range(len(buf) // self.block_size):
+ i& U6 `% l* n/ u2 N# x - self.ioctl(6, block_num + i)
8 W& s( l1 d/ Z - offset = 0
# H" y+ J; g/ Z( p" m$ m - addr = block_num * self.block_size + offset
1 X, e9 Z9 h; t% `! K% |# _ - for i in range(len(buf)):
& g E# A! F1 S: e - self.data[addr + i] = buf[i]
0 c7 \. ^% _ D3 P# f
* |! t7 k) O; D9 j- def ioctl(self, op, arg):
o# Z# m H- \ s - if op == 4: # block count9 F1 Y: K; v! ~9 F. j7 l
- return len(self.data) // self.block_size0 M1 T0 q, ~" N% F' m2 n
- if op == 5: # block size7 E' n0 h5 `" M4 Z2 F7 Q% b& I
- return self.block_size
3 t3 j) B) k; i; f3 y8 K Z - if op == 6: # block erase
' J0 }- u) y7 n; Z - return 0
复制代码 # l: I; G1 b B# r8 X6 F
2 v$ D- Q1 {7 c6 |$ x2 |9 a, t0 b# G8 ~- L ]9 h8 s' M+ P. ^8 U
由于它支持扩展接口,因此可以用于littlefs: - import os2 s* c' M% g7 @ C- G) u! F# }4 i: G
- + B9 H0 I4 |; A0 ]$ I) C
- bdev = RAMBlockDev(512, 50), Q: F, v$ }) E) ^3 J2 v
- os.VfsLfs2.mkfs(bdev)
9 \/ O5 P/ E9 [0 K - os.mount(bdev, '/ramdisk')
复制代码 7 ]( c( V3 u& B# o; {+ t9 b
8 |7 T) [7 a" x/ }( U- R5 }& V
( m, c; O. v h% m一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:' Q# P$ `, ^' [$ \6 X6 ~! w3 z
- f.write('Hello world')9 [, p% f6 ` r ^! L. |
- print(open('/ramdisk/hello.txt').read())
复制代码
% `: S/ D1 {0 G. S! D6 r: z/ B4 Y5 P' U. K/ S
0 H, E( S# C) I( L
! V) \8 o) ]6 t* F7 [# L$ G+ R" _* K% N }+ c: T6 Y# m( p
文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。
! _# C4 S6 }9 {+ `FATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP32
) c6 A) l0 G, h! L. l- D - import os
" l! a' w+ y$ `& M* I/ n - os.umount('/')5 P+ Q1 E) u5 `" v# Q+ c
- os.VfsFat.mkfs(bdev)
' S/ [" _5 C3 w8 j - os.mount(bdev, '/')" x1 l+ k E8 _$ w$ x
4 Y9 ]2 H1 t+ {' A( w1 Q! h) w- # STM32
: p/ d. ?4 c; q+ Y/ h1 T8 Y - import os, pyb4 s7 ~7 R: `1 Y& {+ G
- os.umount('/flash') d% _- L8 P L
- os.VfsFat.mkfs(pyb.Flash(start=0))0 L6 D- y" k1 h q8 N9 D
- os.mount(pyb.Flash(start=0), '/flash')$ n1 B- x! B' y" Z5 a
- os.chdir('/flash')
复制代码 0 {: p. N4 D! _5 W
& `, C0 S- a8 f5 R
; \& L' L2 n: J+ z% \" X% x
( n. N0 V5 v( y/ f- F2 wLittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295.
7 B+ V5 N8 o- t+ ^* W; t' D注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP320 t: ~0 k# `; }& ]. m
- import os
8 o4 ]) @4 w7 o6 J& A: k7 F - os.umount('/'): [4 s1 h$ |0 m! h! t. b* ~- Z
- os.VfsLfs2.mkfs(bdev)
$ U; @/ d, g9 \% p# h; U - os.mount(bdev, '/'); E9 r' ^! }- K4 Q5 C
- . g: W; f6 X+ `; B
- # STM32
/ J. U0 V% T+ I1 C1 q1 I3 c - import os, pyb
) K$ J$ k6 y- U) ?9 f, ~8 K - os.umount('/flash')
/ B+ n! I9 k a! a. m1 ^& f3 F - os.VfsLfs2.mkfs(pyb.Flash(start=0))0 t9 @% U1 a4 U5 C
- os.mount(pyb.Flash(start=0), '/flash')7 d: L, H8 q0 |0 [0 n
- os.chdir('/flash')
复制代码
: ]) F! P' F1 p. y g& M5 Y) R/ M+ M+ s. P8 e @# X0 C$ }
9 s3 _' w' v9 ~; T' a3 A) t' `( n0 [) O( R$ h% a
混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb
, e- O0 q/ @ d3 @5 Z - os.umount('/flash')8 |- i/ G& }3 I K$ t5 }6 L
- p1 = pyb.Flash(start=0, len=256*1024)
; `" F0 ~7 a( L' a6 w - p2 = pyb.Flash(start=256*1024)
% E; ] w9 t# A9 i - os.VfsFat.mkfs(p1)
6 m: d; N- e" x3 | - os.VfsLfs2.mkfs(p2), _1 N, B7 U0 `+ U H
- os.mount(p1, '/flash'): i% Z! @) `+ Q3 k
- os.mount(p2, '/data')
5 l+ J) \1 T/ g0 a7 p5 K - os.chdir('/flash')
复制代码
+ X' x; A: E Y/ e2 U m% G
# |) \: M; v2 n; D8 l
0 g, h% ~& o6 a0 c1 ~! A, {这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb
+ z; [* S/ U( u" ^ - p2 = pyb.Flash(start=256*1024)* r5 N5 [7 I1 o: d7 g+ D% {+ u& ]
- os.mount(p2, '/data')
复制代码
7 h7 |6 p* ? T& N2 h& V: K6 }
4 j/ ^5 q7 m: U& ~; `9 G& v: l/ Q+ R* F- |3 p7 E
来 boot.py挂载数据分区。 & N+ j# g" p; _- S( H* {+ e
混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os
, ^2 x. z' j u z - p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')
$ u2 z( H) S y& A! g - os.mount(p, '/foo')
复制代码 $ X+ Z" }4 s: ~
, M& Q& }$ X7 z; F T
( V# I1 C4 _( X5 ^
3 Q7 Y6 T+ a/ D, F. a* k8 h! N" n9 t5 y$ v1 J) c
/ a& F( S, L2 f; G
|