使用文件系统 内容 使用文件系统 , z5 r ]0 _1 w) s5 s" X
虚拟FS 块设备 * m$ l, I1 d2 T' V: k3 y( G4 ^
内置块设备
; k* F4 x1 p- `3 e( r8 U, y自定义块设备 4 G# T4 B1 W3 j5 X6 @9 ^* O5 L9 S8 H
文件系统 2 `* r& D) `9 w7 j4 G5 r7 G
7 n* e* t. F, l" C# o a
: ^. g, `% i. N0 m5 Z& o; z
) _0 U+ j5 A! 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 上,主文件系统挂载在 /。 / F5 I* G, ]; v* P
块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。 - l, u+ k M+ ]4 A
ESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。 / w! q7 U- R7 y) c/ R5 C. T/ b6 q
ESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。 ' f+ Q8 t( ^ L' z! e4 y) F
" H, \4 v5 z. b
自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:6 J8 z' j/ e( z( S$ k- U" q
- def __init__(self, block_size, num_blocks):/ R/ K. |4 ^# }, d; [
- self.block_size = block_size5 Q1 u; l( f) Z% y& F* F
- self.data = bytearray(block_size * num_blocks)
5 R ], o: d0 v" a5 \3 Z - $ A, @7 e# B" \" P. h
- def readblocks(self, block_num, buf):+ l, R+ m$ ~6 o, O' ~! c' |7 I
- for i in range(len(buf)):
, |7 l+ e1 U9 `( g - buf[i] = self.data[block_num * self.block_size + i]
: I/ x8 m- M8 G, z$ A
+ i$ a( N7 l3 j$ _1 o4 b- def writeblocks(self, block_num, buf):' \ d1 [" @ a! C: `) j8 Y
- for i in range(len(buf)): O; h$ S! c* _7 U5 w# x" H
- self.data[block_num * self.block_size + i] = buf[i]
1 {+ v% {8 E" f. N
$ U0 S; I# ]2 q7 _4 u9 Q- def ioctl(self, op, arg):
3 ]0 @+ M: p4 n' S& T( l( D - if op == 4: # get number of blocks
+ d) I- K8 h' S% z# M) S4 v4 u - return len(self.data) // self.block_size
2 Z7 a- ]4 i) [7 T7 w - if op == 5: # get block size
- w( T6 S6 Q! t0 [7 d/ u, G - return self.block_size
复制代码 + @( f0 Q, S0 w8 U9 i6 }* V
5 v) ]! ]6 \1 v3 v u3 w) Y$ n0 Q% H9 c1 u/ g! q( Q0 S0 N
它可以按如下方式使用: - import os9 \1 L( ^, `* k% R. l/ N" L
3 X: |+ ?' P3 F8 q9 a3 O8 W+ m4 D- bdev = RAMBlockDev(512, 50): j; o ~$ \8 g
- os.VfsFat.mkfs(bdev)
9 E' {* {1 {# |' }7 [+ Q! m - os.mount(bdev, '/ramdisk')
复制代码 & ^1 o3 E* c4 L9 s/ c2 d9 O- p C2 P
$ g0 c5 K# ~( w4 E5 s
7 X- z& ^. c+ [% s$ ]+ K/ D% _9 {
支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:9 S: @9 ~" N3 T N% g
- def __init__(self, block_size, num_blocks):
% o/ y& N; S( E3 x& @ - self.block_size = block_size
2 y' L3 X9 p$ s9 f# h - self.data = bytearray(block_size * num_blocks). H0 L9 v% j- f) T
7 z$ P" E( E6 S9 f- L- def readblocks(self, block_num, buf, offset=0):
1 d* K0 c) n4 `" G9 l; O - addr = block_num * self.block_size + offset, s/ T2 ?7 [! S, A! b, ]
- for i in range(len(buf)):6 s# v. a: U! |; E3 D' I, d7 h
- buf[i] = self.data[addr + i]
5 e6 J$ y. I1 M
; Y9 {! u: K% [! d% c" ]3 [- def writeblocks(self, block_num, buf, offset=None):
2 Z( W& w+ j" y4 t& ~ - if offset is None:
/ f2 _4 n" `. Y/ a& X( ^ - # do erase, then write7 B/ g; B0 i, R5 I- Q0 b
- for i in range(len(buf) // self.block_size):
2 W, w. W1 n$ D2 N( V - self.ioctl(6, block_num + i)+ W8 o; V3 D, O
- offset = 0
) W" d8 v. \0 K U# q - addr = block_num * self.block_size + offset
! m4 _' B5 Q+ ] - for i in range(len(buf)):5 B/ N1 L4 Z5 r7 R! d% T
- self.data[addr + i] = buf[i]7 O! {4 A# y9 l& I3 F
+ y; `7 F9 \" _; S/ ?- def ioctl(self, op, arg):
) _# A9 c/ Q1 b0 K - if op == 4: # block count
3 d' t; Q# `4 S/ c) Q9 D0 ~ - return len(self.data) // self.block_size
9 i3 r- J/ w" p0 J$ _' A3 E - if op == 5: # block size9 \( H) \% n) Z5 R7 |7 r8 e
- return self.block_size
8 S D7 p K' L9 y5 m: c( H - if op == 6: # block erase
5 H( H, l5 E v7 o - return 0
复制代码 9 l; Q0 j4 K1 M' l! l6 g" V1 o
1 d2 [$ e+ @6 @% C6 k2 M% U, F0 O# ^8 x& Q/ ?( w! y
由于它支持扩展接口,因此可以用于littlefs: - import os4 L, ^9 t8 E/ E/ i
- * ^$ O ~8 J2 r
- bdev = RAMBlockDev(512, 50)4 g- E6 Z6 O; J7 y# r
- os.VfsLfs2.mkfs(bdev)
. e5 X' U) x7 S7 ^ - os.mount(bdev, '/ramdisk')
复制代码 # q2 J# H2 u1 \# K! q
0 z* ^2 r8 C: T$ @" |% v3 w. o/ K& f! D4 E# g6 `* q1 ]
一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:
) y( J% p$ q3 T; y - f.write('Hello world')
5 }& a% ?( E' q! @ - print(open('/ramdisk/hello.txt').read())
复制代码 $ ^$ M Y x5 H- p: X
& @' p' g* M2 _
7 X3 Y. V7 @/ m
3 ?+ ?- [( {# Q* P+ x* J
6 R( u; v8 B- e1 E3 u! F8 l2 Y, Q/ n2 ^
文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。
$ ]% n' |6 f4 v. {2 |FATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP320 _5 J6 }+ \) }( h: N
- import os5 q. a. c- {: e% g% x! V& s9 | ?9 M3 Z
- os.umount('/')
8 r+ y9 e% v W S - os.VfsFat.mkfs(bdev)& h4 F+ c. V4 ~: H! X' Z {
- os.mount(bdev, '/')
) D- R1 E5 Y5 r1 G9 a n$ s0 y - 2 y$ t4 I0 s7 |8 y+ Z8 l8 S3 M1 p
- # STM32
4 h& p. S; Y% G i - import os, pyb$ |- P3 l5 Y; O3 U1 U2 w- v
- os.umount('/flash'). C) ]) i1 H: C1 g
- os.VfsFat.mkfs(pyb.Flash(start=0))8 R7 ?* k0 G0 J
- os.mount(pyb.Flash(start=0), '/flash')
- P+ S- l4 W# _9 @& z - os.chdir('/flash')
复制代码 + ~$ I/ o0 a5 A6 _* o: Q
- H' S8 E" t( P. A# R
- ?8 ~* l' E' @8 N
0 \$ Z% \$ ]& z) V0 `' rLittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295.
' i& t& U+ R% r注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP32
; L& b- y( u& ?6 r% v - import os
' \; r& k" l2 f7 b1 e7 o& \& ^ - os.umount('/')0 Z0 D2 ?" }; t. @) S3 g
- os.VfsLfs2.mkfs(bdev), A5 E+ Y$ C: b* O0 q' N
- os.mount(bdev, '/')
# [" `2 A! N! d" b$ T
$ u4 w) p2 m: s- # STM32
6 S4 m* H' Q8 b+ ~+ f5 D- r - import os, pyb
1 f C# [/ c5 G$ N6 S - os.umount('/flash')
& H4 e( `0 V% i2 j' f0 a - os.VfsLfs2.mkfs(pyb.Flash(start=0))2 f, X4 }5 H4 K9 |
- os.mount(pyb.Flash(start=0), '/flash')# H7 {$ h" B3 v. a
- os.chdir('/flash')
复制代码 . S1 N; H. Z+ a- L# q
. j# z/ V% Z( }0 N
* s2 _% b: W) \- x7 z4 z1 Y
2 A. i+ L8 C3 Z: p/ b% P, L- E混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb
/ |' q- q, V$ \& j8 q% {2 T' J - os.umount('/flash')+ {4 W6 ~% {2 U G/ E; D. R
- p1 = pyb.Flash(start=0, len=256*1024)
5 Q/ X; K X) T( m/ @, f: P - p2 = pyb.Flash(start=256*1024)
- Z# Y3 I6 U& B+ P0 d. |8 n0 T' B - os.VfsFat.mkfs(p1)
. G* N) F! A4 c( q9 N - os.VfsLfs2.mkfs(p2) `; F- X& |! \" q7 m. Q
- os.mount(p1, '/flash')
# {! Q/ D8 i7 Z. f1 z+ ]: }" x - os.mount(p2, '/data')
1 M' f* n8 ^# a1 m1 X - os.chdir('/flash')
复制代码
! U! y$ \) ^# Y7 D$ \$ l: T% L1 T1 d; D
7 x& @' K4 g% o! {
这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb5 h8 h& E: V% r: \+ W
- p2 = pyb.Flash(start=256*1024)
' _$ u9 Z4 U4 V9 Y; ], v) Z4 H - os.mount(p2, '/data')
复制代码
5 ]1 t3 Z' F' a5 i& I7 X+ }. x, z8 D2 T6 B: _5 ?* D- j
( D+ i$ h* k7 r' R, b$ a& T1 t, `
来 boot.py挂载数据分区。 ) }6 j" _- }% v3 t1 V8 R* B5 w9 ]
混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os, l; K# N- }; h1 ?5 Z
- p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo'), w" D+ X! o. T& n- ~" k
- os.mount(p, '/foo')
复制代码
7 X. U# f; c2 C [) n; N5 I" I( P+ _& E4 q
8 N8 Y, f$ y7 ]. Y
1 l; Q, y) Q6 _: A' `3 }! \5 q) N' S! L, g
- n, Q, _) H' H+ G, _
|