使用文件系统 内容 使用文件系统
8 I9 H( `1 M1 X) v1 X! {: R- m, u虚拟FS 块设备 : M9 s9 a e% X
内置块设备
. \4 T7 ] q- j5 T" Y8 W! O \自定义块设备 4 d3 v8 T1 Z7 v/ D7 P' a
文件系统
2 l- v: u6 _1 n: @% L. e( Z0 a Q/ [! W/ ^2 U
0 r5 {0 \ v' R& W* u; e6 p" c
$ W0 Y; T9 M5 r本教程介绍 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 上,主文件系统挂载在 /。
4 j R4 t, E5 P! n3 Q! ~- x6 i块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。
1 K2 g+ f( C% M' d1 B9 B# ]ESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。
% x5 t& v6 f) m g* v* eESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。
3 q; | D3 d/ l5 \
" ]0 F* ^' @+ m$ q8 _0 q" U自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:9 e6 w$ B3 T# y6 I' o7 E
- def __init__(self, block_size, num_blocks):! I% d$ t6 a, v8 ^+ i( k# W
- self.block_size = block_size& F' d; T7 [/ F! a) {5 b
- self.data = bytearray(block_size * num_blocks)3 b2 j/ T/ \. K3 b" N+ d. `/ f
- 4 I( r; Q$ A' t+ C7 c3 M
- def readblocks(self, block_num, buf):; f1 T& S% ^" \: j/ Z, l
- for i in range(len(buf)):
+ c+ F3 x- C: O' n/ @& v - buf[i] = self.data[block_num * self.block_size + i]
1 G( T' L- \; r' Q5 j
0 H. T' w! n# T0 x" E- def writeblocks(self, block_num, buf):6 l1 ~7 U. m4 W
- for i in range(len(buf)):% s9 o% s' q1 o) c7 b2 O
- self.data[block_num * self.block_size + i] = buf[i]
4 u: z7 ?, G D% Y! g
f/ ~% }" k$ P; [+ i- def ioctl(self, op, arg):
/ r, R2 ^1 G& b% I# U4 r - if op == 4: # get number of blocks- S D2 ?" U, |- ~( t; x( c( l! t
- return len(self.data) // self.block_size
5 n( B. A( ~: G( \ - if op == 5: # get block size- o6 |" r5 n$ l2 }
- return self.block_size
复制代码 3 o7 F* ?7 h7 a2 A' t5 W3 k8 y
; Q. N" N: q9 A Z' k) d
7 D$ C7 r0 v) i) t它可以按如下方式使用: - import os
1 E2 \% y/ H2 ]9 |
+ [+ c* s" y0 N) j5 P# m' K- bdev = RAMBlockDev(512, 50). o! ?3 V. B3 }2 i' M
- os.VfsFat.mkfs(bdev)5 h2 U7 t" f1 C3 B I& ~# T6 J
- os.mount(bdev, '/ramdisk')
复制代码
- [4 A$ F. a: X( n" N8 W7 j9 W7 h3 D1 i( ?8 m# k
+ ^8 Q9 C5 V) j$ y支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:
9 D, e2 @- G- q$ [& J2 } - def __init__(self, block_size, num_blocks):
, a0 G/ \( |) M# l! N9 u - self.block_size = block_size' v5 u9 D0 @8 r- `' t( D1 R8 v
- self.data = bytearray(block_size * num_blocks)
/ Q! N' i; W4 y1 I$ q( F" ]) H - ' S) l |; i4 v( u( h6 W
- def readblocks(self, block_num, buf, offset=0):
* H! @( C3 H8 l ~$ F5 r - addr = block_num * self.block_size + offset
$ U7 f- ]/ ^" K( }3 r - for i in range(len(buf)):
( g. X4 G4 q& D, I - buf[i] = self.data[addr + i]
k" ]$ i b) X
( B. w: b, o# Z8 V( H4 \4 t6 `, N- def writeblocks(self, block_num, buf, offset=None):1 l8 h z3 |. O- @5 s
- if offset is None:- j, b; A. S% i9 t
- # do erase, then write% e6 x. E6 E$ Z: Y3 c: q0 Z- R
- for i in range(len(buf) // self.block_size):
' i$ q+ f4 F. j1 H- ]/ |% y - self.ioctl(6, block_num + i)5 I: ^+ ? w' ^! @
- offset = 0; G$ w, q! r. W. P. Q7 V3 B" p$ d
- addr = block_num * self.block_size + offset' Q( r5 |$ V b! w0 O6 F6 f' Z
- for i in range(len(buf)):
: A' @4 ]2 J- ~$ Q7 } ]( ?# Q7 P - self.data[addr + i] = buf[i]
% @9 h0 C0 C4 S% ?. w9 m! L
/ ~- P- |8 K* \! Q- def ioctl(self, op, arg):
4 x! i7 M; |1 R* a9 \ - if op == 4: # block count
+ A! n5 m+ |' s8 S+ R. B$ a - return len(self.data) // self.block_size: O! d- K5 o, ? r8 f6 ]# C6 N( b
- if op == 5: # block size" R" F- H, R" k1 \% r8 P
- return self.block_size1 E& S4 h# q: u8 ^: n& O
- if op == 6: # block erase
3 S5 x7 A- _* h' g! M! s - return 0
复制代码
! t4 f. M7 h s9 T
! v+ M4 y5 ]; P6 d5 E; Q& B: m8 {7 z$ A5 t" L
由于它支持扩展接口,因此可以用于littlefs: - import os7 M7 B2 l, Q0 h/ k+ ], h
- 9 Y4 G" N$ W) m8 }
- bdev = RAMBlockDev(512, 50)! G7 U$ F+ }- D6 [& |) R; K/ m
- os.VfsLfs2.mkfs(bdev). c8 a/ d1 y( x
- os.mount(bdev, '/ramdisk')
复制代码
7 C$ B3 B8 @+ I5 v: W# O1 `: R& e- }( s- c: E
. C" ]# Q _* r8 o% G一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:$ M! Z* ^9 l# H- [) D5 G2 I
- f.write('Hello world')' l# _' L- ^ J4 r5 x$ v
- print(open('/ramdisk/hello.txt').read())
复制代码
/ T3 B6 ?. k f! U' C* M' n5 ?3 d g' ?* ]! T
) P5 z2 t1 I5 j6 h
6 D( o# e. L0 _+ h% D6 P/ s$ Z/ B
0 J+ _& A) }7 v8 P: @9 r文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。 7 S* T5 N) B$ M8 r
FATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP32
z6 p- o. M( b" L/ i - import os4 Z7 T# M6 ?! [2 N/ Y8 H
- os.umount('/')
% N" f( X0 k3 @ - os.VfsFat.mkfs(bdev)
/ f- \: Y1 Y6 ^1 g! y6 \3 [ - os.mount(bdev, '/')
" g( r: F/ a C" h4 ~' p' d/ e
; Q. F7 O u. P8 l- # STM32% Y& c' ^0 @+ Q+ y
- import os, pyb
( {, a. v9 N0 k/ l: j8 @, j; I8 W( k - os.umount('/flash')- u& [6 U2 N8 w7 |1 B9 y
- os.VfsFat.mkfs(pyb.Flash(start=0)). B. D% K" \. N. s: R& B; v( _# _) s
- os.mount(pyb.Flash(start=0), '/flash')) ]9 M0 J7 u2 D2 ]
- os.chdir('/flash')
复制代码 6 |) f+ f+ g1 z
0 o5 [1 T8 R. O% m |: r! v5 u8 j! ^" i+ ]% ~: M
' N9 t+ f7 ?! Z j% N5 P' A8 G* v8 X
LittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295. $ |. U+ F& c# Z z; T
注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP32$ d! o( e$ D1 Q4 @
- import os
. N. I3 U: U' b3 D0 v - os.umount('/')2 r: U* n# S$ \, K; |$ E
- os.VfsLfs2.mkfs(bdev); E; X" C2 N n5 S' g4 ^
- os.mount(bdev, '/')
: ~! _0 w% y0 ?0 {3 x, }5 P
# C* q6 B1 u/ P& j1 p3 p) s( j- # STM32
3 j# u( @1 f) r2 @7 O! \7 `7 n# h- K: A - import os, pyb
; g' d+ Y3 F, B$ [+ i& L - os.umount('/flash') A0 Y. L0 D5 J! q
- os.VfsLfs2.mkfs(pyb.Flash(start=0))) l6 _ W" d, Y
- os.mount(pyb.Flash(start=0), '/flash')
1 ]$ L! D5 `5 x, M7 ~4 C - os.chdir('/flash')
复制代码
5 _3 ?; ~. Z4 {8 w% F/ A& ^7 T. Z: C' ?
$ [ L5 f! q7 L* ~" x! p9 C2 ^
$ s% o9 E$ W8 U% q! ], {混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb; l3 L6 ]4 B# f9 ]4 n- e/ e
- os.umount('/flash') v& E/ ?3 T0 b$ I+ u
- p1 = pyb.Flash(start=0, len=256*1024)" t3 Z) p- y& }9 \
- p2 = pyb.Flash(start=256*1024)
/ T+ e! r% C. x; ? - os.VfsFat.mkfs(p1)
& r* Y3 H/ }9 ]9 s, N - os.VfsLfs2.mkfs(p2)& H1 {. E T- H+ o: S
- os.mount(p1, '/flash')" W8 J9 R5 f" _- g) c6 B2 }
- os.mount(p2, '/data'); L6 r* _& |/ a8 t: V) T. I ?
- os.chdir('/flash')
复制代码
( U: b; d, ?% o6 ?6 u
/ b: X8 E. y. J! N0 Q' n ] x6 y2 q$ i! V9 ^- ?5 u
这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb5 e) U5 o z5 J- ^" R' L
- p2 = pyb.Flash(start=256*1024)7 |& f; |8 h8 M6 l8 l+ d) j9 ]
- os.mount(p2, '/data')
复制代码 % }: m1 e! p" K) H H( A) O8 s( n. P
( [* P4 r8 @% ^4 H- {( y+ @) n% ]" Q$ [ F+ C( `% }8 R+ M
来 boot.py挂载数据分区。
) A8 s; i8 f' k& s) L0 l$ k混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os
& ^ X3 A! V: o: M( s - p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')
: e# `' C3 O) _ f - os.mount(p, '/foo')
复制代码
2 G* A) y# s8 B- f' \' {3 m8 O7 D W( x9 P/ C
1 `# ]1 d; P" o N8 O8 n2 N! x: @. I% g3 e# D. o
) I: ^! G: G, k2 Z3 `4 I, ?, W) c2 S) ~! G. [
|