使用文件系统 内容 使用文件系统 ( ?. J0 r( x6 C5 e# Q( X
虚拟FS 块设备 , u9 f1 G+ Y0 j; l! b0 q
内置块设备
6 g* R! H, o- _& t ^! D, V% |自定义块设备
! A2 S, K* r; ^7 E S& g. F! x
文件系统 8 E! B/ P) ~3 ]4 _! T$ A
' o8 q6 G3 y: x; N
& z6 T% p" P d4 o( d# L ) K0 O6 F4 h3 X" 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 上,主文件系统挂载在 /。 1 z; E+ @5 V. k
块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。 8 o* M5 \( U/ C2 X* q
ESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。 - h; G( I) C4 ^6 w9 o/ s, @* `
ESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。 + ]" D4 {( o6 H% p6 h
) _( \& M8 u! i- `+ ~: W# I自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:7 ]7 F, K4 m" W7 z+ l7 q. ?
- def __init__(self, block_size, num_blocks):
/ F! t1 ]* A& A( k - self.block_size = block_size
8 _; L8 P, C) l1 A5 [* M' l8 m* K/ T \ - self.data = bytearray(block_size * num_blocks)
, o& J6 ?9 n% E, D% M1 c
- f/ v P7 h: k! ^4 |- def readblocks(self, block_num, buf):# E; v6 N% ~5 ^
- for i in range(len(buf)):7 q- H c) Z Y4 O1 G, A$ s0 N0 D' D
- buf[i] = self.data[block_num * self.block_size + i]
7 W. R, w6 W4 h- ?3 }8 y - % ^9 R% C3 @! P/ K- K
- def writeblocks(self, block_num, buf):; p4 ?. @* v3 \) u5 F
- for i in range(len(buf)):0 b ]) g5 n) I5 _2 ^! r7 H
- self.data[block_num * self.block_size + i] = buf[i]2 R' B( N+ b/ d! G- h& U U
- x0 f2 ^9 J3 c# c- def ioctl(self, op, arg):
: o% B8 h% R4 B( E - if op == 4: # get number of blocks! E0 {- @, c! J5 E% G
- return len(self.data) // self.block_size$ P R5 D1 {! m7 X& w. \
- if op == 5: # get block size
: M& G9 M) A% w, o4 Z - return self.block_size
复制代码 7 y- F, Z* V/ p" {8 _
" Y+ @* { c/ n5 J
- Q1 R! q) H# T6 d0 [4 f3 _( g: L
它可以按如下方式使用: - import os
; R0 O* Y" w. c% V. Q8 {
4 J4 q& x* k. x! d7 e( W2 q- bdev = RAMBlockDev(512, 50)# ^ S1 |- e2 j- W1 k4 R' c
- os.VfsFat.mkfs(bdev)
/ ?' H4 h. R2 S: M - os.mount(bdev, '/ramdisk')
复制代码 ) d u7 D! z- e, k" c/ D% I
J1 u5 ^, O) v4 T! G5 p0 h
! {' F# z1 W) I+ _8 F+ T6 U支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:
# ^9 m$ A0 I" h' H! ]/ W - def __init__(self, block_size, num_blocks):
/ r; R9 V7 P- n# E - self.block_size = block_size f# O4 I+ i; z- Q3 y
- self.data = bytearray(block_size * num_blocks)5 q2 S8 f9 \3 X4 W4 S# q/ J
- 0 X* {, r* k4 f5 f& s5 {" F
- def readblocks(self, block_num, buf, offset=0):
: E9 {6 L' J9 |# u( w0 N - addr = block_num * self.block_size + offset
M# J3 m o- ^' n& B - for i in range(len(buf)):
) F1 N( I% W' V8 [ - buf[i] = self.data[addr + i]
w0 ^9 X& G3 ?3 p, L8 K
% C8 d5 E E3 V- def writeblocks(self, block_num, buf, offset=None):
7 z+ z2 U1 H% v) F' J - if offset is None:
- c" P+ @; ^5 k- N - # do erase, then write
+ g' g. H! e: h9 t3 |, k0 P - for i in range(len(buf) // self.block_size):6 i1 l9 q" ?+ C* z0 b$ J; h
- self.ioctl(6, block_num + i)1 ?; G# D9 p Q% P/ i5 v
- offset = 0, x6 o' L: F$ M. N+ o: @/ w
- addr = block_num * self.block_size + offset- C: \- s$ M( a5 Y0 [
- for i in range(len(buf)):' e. K6 |& |& d/ [: O1 e3 H' y
- self.data[addr + i] = buf[i]
/ l) U7 m& S! \' f% T2 M7 @4 Z
7 c. M1 U: }5 `3 _& r9 \- def ioctl(self, op, arg):
( f4 N3 y4 G+ x2 R' w6 D* q - if op == 4: # block count
+ A+ u4 ~" l0 E - return len(self.data) // self.block_size
% c# v/ ?* J& S8 X - if op == 5: # block size2 @) ~, p8 o& g& |& f
- return self.block_size( ^4 H8 R* ]) v7 u5 p, ]3 a9 E
- if op == 6: # block erase+ N( @5 T0 I3 \( @
- return 0
复制代码 , |' G1 w- y4 W* h2 C6 `$ t5 `
, p- a6 v! T/ F7 r
+ s* H' V: [/ z& ], O# l3 F) V由于它支持扩展接口,因此可以用于littlefs: - import os4 |# H; ^. {# B0 m$ i, o7 ^- P
- ( F7 T; i; w4 ^/ T
- bdev = RAMBlockDev(512, 50)8 a8 o( w" y ?; J: G' y2 K6 N: {
- os.VfsLfs2.mkfs(bdev)
" t0 c7 S# ~; `& J0 J - os.mount(bdev, '/ramdisk')
复制代码
0 f5 |- f+ z+ C$ N h2 f
b9 Y: A2 A3 y0 k3 t( v0 j4 }+ A) m1 m& N
一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:
9 S; e4 W, R) y - f.write('Hello world')8 v" j4 Y- K3 S$ `0 ]+ R4 Q
- print(open('/ramdisk/hello.txt').read())
复制代码
5 ~7 t! z( f5 M
' @' E8 X i( |) l6 y% R/ a( o# t8 S9 Q ?4 l1 e8 x$ O
! D: Q# k" B0 M# s Y
; w. C% D; m# {2 c$ B# p5 I* d文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。
- I* z- c& e1 u) i1 h2 a% a* O* yFATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP32% N; P. i* E6 {5 y- O
- import os2 r" ~; G* \( _4 _% m' X
- os.umount('/'); Z% M$ g8 x* X' T3 a
- os.VfsFat.mkfs(bdev)
2 A6 Z# G: v8 ^ - os.mount(bdev, '/')
; P6 z6 U+ g1 h. B) n* P: D7 E
7 x: ]( y6 C1 L; d2 ]# a# v5 `+ p- # STM32; k0 r* H6 @8 j( l, q- a
- import os, pyb
7 D5 L: ]. V' p" B$ V - os.umount('/flash')5 E9 P) [: h) }( x+ J; x& b4 h
- os.VfsFat.mkfs(pyb.Flash(start=0))4 _- X2 n- V7 L3 T
- os.mount(pyb.Flash(start=0), '/flash')) t! |8 B- h8 Y5 `
- os.chdir('/flash')
复制代码
8 z# g5 M/ R7 j4 y) U' w5 q- \3 p3 T7 n' r; r0 ]+ O
1 G# Q( j; X7 e- g/ c" j7 h# T0 l
/ Z' s5 [ l+ {% o% {. X+ cLittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295. & D) W& L/ H$ o% S- `7 W, w& l
注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP32* T# z! D3 r% ~6 l) a
- import os
% H4 {" T3 r( D& c: C - os.umount('/')9 x7 D9 t0 B* y
- os.VfsLfs2.mkfs(bdev)
$ B* t: L. u4 m _ - os.mount(bdev, '/')4 d$ e! I$ W: ~, q
- 4 a# g5 B* w" ]5 A5 R9 O
- # STM32
% S5 l" M1 D( J: M8 v) u! f - import os, pyb3 b. T9 f1 z" `) q
- os.umount('/flash')
7 H7 q# b( y& A' C3 q7 Y, y - os.VfsLfs2.mkfs(pyb.Flash(start=0))
: J3 P4 V1 m+ R' v5 G - os.mount(pyb.Flash(start=0), '/flash')
/ g8 V+ c7 ?2 @2 R; l- f3 F1 H - os.chdir('/flash')
复制代码 ! X; h8 y/ J- h
. e( @1 _# t7 N4 n) C- q9 I& f4 j
o, W$ B. X) p/ o
/ d" T# H. I2 s8 H2 f( K1 X# J; v
混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb7 M% G% X- @9 O( ?% |, c* o
- os.umount('/flash')
& Z5 o5 T/ D* P( i+ u - p1 = pyb.Flash(start=0, len=256*1024)+ z. N$ G* U. f
- p2 = pyb.Flash(start=256*1024)
- a1 `2 h4 M, _ - os.VfsFat.mkfs(p1)
e" m; E: ~/ b5 F - os.VfsLfs2.mkfs(p2)8 }7 Q# U+ B, z x. \0 O9 h
- os.mount(p1, '/flash')
6 s+ W' v/ t" P, E$ v3 v' [$ T0 ^ - os.mount(p2, '/data')
8 ]& R( J) L+ V5 o5 N$ {2 H# Y! D - os.chdir('/flash')
复制代码
: x* \- Z8 i6 B5 U8 W) l$ i. H
8 K+ y4 H; f1 f) Q
J; i1 f6 h7 ?! u这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb7 v1 M- ]* k$ |7 ~
- p2 = pyb.Flash(start=256*1024)
# k0 U1 O1 g' d+ _4 v! r' r - os.mount(p2, '/data')
复制代码 8 ~% p4 x' c/ N* Y+ u6 z4 o2 i
. i+ `1 b: O1 U; x
# S) r% I; p, \来 boot.py挂载数据分区。 9 C+ U( E8 k5 g, D$ U
混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os& b6 J6 @7 e6 f& ^% @( q6 P
- p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')0 H" k! B5 B b# n
- os.mount(p, '/foo')
复制代码
& }. e E1 v6 X/ |
0 o% ~. U0 Y+ r' D# E" u `/ l7 u8 K7 f. K7 Z# S8 [+ h
4 N6 W# y# |4 F- F# z6 F
9 |; M' j* b$ I( X4 w5 Z1 X, m, F$ ~5 k" j' \! |
|