使用文件系统 内容 使用文件系统
) B, C- t Q# t5 I! p虚拟FS 块设备
+ L3 k: k7 t" v, p0 q2 f" v7 [内置块设备 : A8 e( o. [$ x. F3 `& ?* c! u
自定义块设备
& ]. {, I9 L4 T- |3 P) R
文件系统
: M8 E8 E1 l2 s$ @4 t. u$ V' t9 e7 U; q! r
' ^" J; \3 }- S! f& ^3 A6 _
5 ~! ]6 _, F6 `( ^" a) 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 上,主文件系统挂载在 /。 % V) E6 H4 q5 U- a' I4 Y5 H- T1 ~
块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。
& a% h- {7 {4 MESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。
- a N% N b5 s$ b& j- C, {ESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。 8 l5 n5 e! e! _6 K
% `! ?8 p2 c6 X! k
自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:
3 M: f; Y: a1 l' j, I1 P9 { - def __init__(self, block_size, num_blocks):5 X1 [5 Q/ G: B6 z. q
- self.block_size = block_size/ V ?, V' S; k4 t f
- self.data = bytearray(block_size * num_blocks)6 [+ f) d1 e0 e- y% [( P
- 1 r7 ^+ `/ }( f8 q
- def readblocks(self, block_num, buf):; W$ p7 f6 C2 I+ u, E1 r' U
- for i in range(len(buf)):* N. }9 z2 l' g- y
- buf[i] = self.data[block_num * self.block_size + i]; {4 z; ^+ c) N# j$ T1 l/ E' v0 U$ Y5 s
9 ?7 ~# J; {. o; F' E: n- def writeblocks(self, block_num, buf):
1 \! o0 a1 ~( O; t - for i in range(len(buf)):
$ g- R4 `: J. _0 \# R }" F# ^ - self.data[block_num * self.block_size + i] = buf[i] H& s; l- y6 h! d
3 _( V3 r( j: h1 q# h+ L: i9 v8 j- def ioctl(self, op, arg):
, L3 b% U, M8 K0 k" C- J; @+ N; o! t - if op == 4: # get number of blocks; K- C- D: e3 D) t
- return len(self.data) // self.block_size" p1 W% S1 O: @) z* u9 o
- if op == 5: # get block size
, L( d# j6 P1 J) S - return self.block_size
复制代码 / x- \ [% \2 o. h" u" ~1 F r, p# `
0 j3 _) w5 d. ?9 [' t* {
% r# Q S9 H$ F, R- _$ w; p5 g- [$ r7 Y/ h它可以按如下方式使用: - import os. M+ ?/ f4 e Y1 M
; P! d; l, M2 R4 c1 m4 s) C- bdev = RAMBlockDev(512, 50)
6 b6 k, q- C2 p# V. J; M - os.VfsFat.mkfs(bdev) K4 w8 x g" B8 w9 i
- os.mount(bdev, '/ramdisk')
复制代码 3 C$ k' d! H/ \' N; N5 i
# @+ {# z2 i+ i$ }4 z* p* \1 k1 w6 V$ T- u* T1 L$ `
支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:
R' N' r" B: H8 a! {# f - def __init__(self, block_size, num_blocks):
. D* j7 ?% F a/ Z - self.block_size = block_size
3 A* o8 u* `8 e( ]( v& X - self.data = bytearray(block_size * num_blocks)
1 S3 ~' [! y: g( l2 c - 6 L- D) j8 N3 v. D6 z1 j
- def readblocks(self, block_num, buf, offset=0):9 O6 l8 v; B: F% J; z8 g, \
- addr = block_num * self.block_size + offset
8 b/ f: A- P6 s, o* l; }0 v/ ?3 u - for i in range(len(buf)):
! U* `4 |0 i2 b* x. U+ q! f' B' t - buf[i] = self.data[addr + i]) O! [+ e2 \( r
- 4 A% z2 n1 w* D. q3 d/ S2 X
- def writeblocks(self, block_num, buf, offset=None):$ y# [8 G e! E3 Q4 a
- if offset is None:+ e4 M3 Y) |6 X" g0 x7 h
- # do erase, then write: O% m2 o5 L/ x& E3 t' |0 f
- for i in range(len(buf) // self.block_size):
- H& k% ?1 x! j& z6 P0 x - self.ioctl(6, block_num + i). Z! K- i0 X+ V! e4 O2 Y, \2 t
- offset = 0, A& O+ z* m; Y; ~; `$ o/ A
- addr = block_num * self.block_size + offset" m! \2 ?- D: H0 ^/ n7 y E1 o
- for i in range(len(buf)):- {+ V8 ^" L0 S1 ~& c& I+ O& S
- self.data[addr + i] = buf[i]7 T- w2 P) h `! y6 n
% \0 ]7 n N$ H6 ?0 J0 }5 E- def ioctl(self, op, arg):' Z, X6 k; k6 ?( d
- if op == 4: # block count
4 }$ Q- |. X9 S+ I# _- [& @8 T - return len(self.data) // self.block_size
% D; r& w0 q. I5 h2 E: P - if op == 5: # block size
) S3 I9 l/ b9 E8 L - return self.block_size
/ N: R+ L+ J& a3 t7 T+ m - if op == 6: # block erase5 i* }' k; d4 e I2 g+ f
- return 0
复制代码 8 N' M- R: {$ W- {. N* V
$ K; ^( @7 f# [, ?) g0 B1 s [
2 `4 k. f* `# w6 x1 {
由于它支持扩展接口,因此可以用于littlefs: - import os
7 V; ?; }' _. } - - Y- X/ g6 l6 y+ w; B% t
- bdev = RAMBlockDev(512, 50)4 M2 p! ?8 z# C, D) H1 L: @
- os.VfsLfs2.mkfs(bdev)) X* L. r, `+ o. w! x
- os.mount(bdev, '/ramdisk')
复制代码 : N# {& q, b' L( Y3 @, ?* J4 V
& Q4 b7 v3 W- V3 q, j) b0 f% n+ q4 ~ Z. C! P
一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:4 ]! J9 x: D" ~2 _9 q. ~$ C9 [
- f.write('Hello world')
$ y+ W# K" z2 e9 q - print(open('/ramdisk/hello.txt').read())
复制代码 - r' a4 s- e A0 D' O4 H
) ?+ Y, c+ I1 g0 L; V* C" }: S
& L3 Z5 o4 l7 M& E2 w5 J+ \
! h" q! N3 j4 [% Z8 ^2 C. w- \
# a% l0 ^3 k# `2 b6 _文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。 5 A3 A+ ^1 ?1 m# a/ J1 L4 e) G
FATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP32# y) i3 j2 }* @3 l
- import os/ [- I2 f* I& U7 b
- os.umount('/')
) c' j& e: c. p+ l, X: J! j - os.VfsFat.mkfs(bdev); v# o9 }7 b/ S7 Z0 r# ]
- os.mount(bdev, '/')
8 a+ P, C q& {
) l) R9 A, A' v4 r9 A7 ^1 t- # STM321 R* z. U% u5 w* B% [0 E7 c
- import os, pyb
8 [6 l# D9 U: Y3 r7 X( [4 R" q - os.umount('/flash')
5 g1 `4 n" _& V7 X5 ? - os.VfsFat.mkfs(pyb.Flash(start=0))
! A6 N# V( P* ?) Z4 R; E - os.mount(pyb.Flash(start=0), '/flash')
% P9 J5 A {. n" N - os.chdir('/flash')
复制代码 # N: R' o: Y* @( z7 n* b( n) f
" m$ D2 V. g. j& K2 m8 j, R
; h* H$ a1 i( `8 s+ g# i; ?( {- ]; ^* m1 H. [
LittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295.
# l5 r1 I) u3 R3 Z3 u注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP32
: S T1 m: x/ P- n- o, H - import os5 \3 P" ]" Z. x9 _. W! V4 S( n% G6 N
- os.umount('/')* ^/ r+ m6 l$ Z4 L! a) N
- os.VfsLfs2.mkfs(bdev)
( T/ N1 f# t/ k$ ` - os.mount(bdev, '/')) Q O; q! W2 s0 {5 K, ?
2 g* x9 v9 C. W1 h* j3 g1 x0 H- # STM326 e7 n5 k" ~+ j4 X* j+ N
- import os, pyb+ z" `' Z `. ^0 g/ Y4 B& \: t
- os.umount('/flash')6 ^0 A1 u$ U. s7 h5 f- L) a9 N
- os.VfsLfs2.mkfs(pyb.Flash(start=0))
0 }! q+ }/ f+ G& c - os.mount(pyb.Flash(start=0), '/flash')4 T5 V; g6 {- M8 g- G* F
- os.chdir('/flash')
复制代码 % H* f% }3 ?8 ~2 z9 V
- p7 l5 \* \# D' F) G& g: S! U' V" L: h. ` ]' w
+ h2 s3 J% |( n" W; ?
混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb
4 C# s$ Y5 F Z; W - os.umount('/flash')
# I. Y. ?3 v, l1 \( U - p1 = pyb.Flash(start=0, len=256*1024): z) `3 T8 M9 Z g1 s0 X
- p2 = pyb.Flash(start=256*1024)! }: f, a9 V2 p8 h: s, F; s
- os.VfsFat.mkfs(p1)
1 Y+ g- U2 H5 R* g3 b - os.VfsLfs2.mkfs(p2)
) V/ N7 E1 _7 V1 p - os.mount(p1, '/flash')
0 n& b0 h% R% U' k \. e/ \# l) A - os.mount(p2, '/data')
$ W V" B. M9 y- |0 B - os.chdir('/flash')
复制代码
( N9 u6 y* b* S: o/ E U, V9 w
$ \/ P. ~2 x9 {' p) C- S" m2 `# a
6 t6 J. j7 O0 z- j# C! U这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb
- N1 Q% |- V/ y, w5 u - p2 = pyb.Flash(start=256*1024)
1 A# i( S7 l; F5 }6 K - os.mount(p2, '/data')
复制代码 $ l) g+ M5 x$ [. E- q( j) N2 J
/ s1 \+ _; ]5 o7 y1 a* y* Y7 |) i: m" \8 V1 g
来 boot.py挂载数据分区。 1 M8 s6 S5 p/ r" }+ \
混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os- j1 a7 [: L. B# d' b+ W/ z
- p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')- ~) ]4 I% l1 I/ w# D
- os.mount(p, '/foo')
复制代码
, |7 m- _3 @# }
0 r5 o S( [$ H! f6 F3 Y% u! ~( ^4 f0 \1 \+ T' m6 W
- b& Q- \ f+ l) L5 G
# c, Q9 |1 I2 M+ }
2 y" Y3 I/ V" `: \ |