使用文件系统 内容 使用文件系统 3 y# E4 _. W. w4 @$ o. @# Y: F
虚拟FS 块设备
# K: Y* O" [6 E. ^/ P文件系统 & G' B& v: ?5 ]4 ?3 v
! F+ W/ }( ^9 D- E% |( N! k
* l+ e4 [4 A2 ?8 T" {# v , f4 W( h- q1 H/ T
本教程介绍 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 上,主文件系统挂载在 /。 ) n4 I5 W7 f/ Q6 `+ N
块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。
3 {. k, t. G5 Z( O( }' S* @ESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。 3 E* \' v D" r* Z
ESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。
4 U2 ~4 x) d8 B* X4 b2 [: n
! M5 S" ?$ J. h, A' Q* f自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev: L& a/ u' z5 {
- def __init__(self, block_size, num_blocks):
7 @7 D6 f0 ?9 i" i) y8 n8 B3 S - self.block_size = block_size
& D. V1 ~- f( W% e7 Z& b- { - self.data = bytearray(block_size * num_blocks)( S+ K; ~( c1 p4 V
( ` G& ]# |" w9 h0 c; `: Y- def readblocks(self, block_num, buf):3 u. O6 D" O% d9 s5 q
- for i in range(len(buf)):
3 H, g+ z7 H. g; _7 m+ f& w - buf[i] = self.data[block_num * self.block_size + i]) p) x3 T! o) G( C$ R
# p# @4 M& C# y0 ~, K& K/ o- def writeblocks(self, block_num, buf):: p0 I7 D( @" S- r, T
- for i in range(len(buf)):+ ]% F' f" U8 |6 f8 i9 k. U
- self.data[block_num * self.block_size + i] = buf[i]9 @( t: [& c+ F0 @
8 `9 Z( ^, X$ ^2 f- def ioctl(self, op, arg):. z# j5 ~1 ?2 f, q5 U+ f
- if op == 4: # get number of blocks
: H# ?1 T* Q# u( J# [6 t - return len(self.data) // self.block_size
! S' D0 d: ^; S0 K) o4 F: G - if op == 5: # get block size
& I+ C# b, d) M - return self.block_size
复制代码 ' }* p2 Q; ^$ e2 o0 L! Y5 J1 j: t
; f8 A+ \" P8 e% r @2 Z. p
/ K' M+ a9 e0 c) o
它可以按如下方式使用: - import os' H b3 Q1 }% ?% B; D/ x
- . u! R- g: p9 @1 K$ o" T2 z7 T
- bdev = RAMBlockDev(512, 50)
" q) C! l, Q. Q7 I! F" L) q. w - os.VfsFat.mkfs(bdev)8 ~! l4 I* B) \6 M$ p; @5 n. h) ^
- os.mount(bdev, '/ramdisk')
复制代码
+ X6 I- K! W; h6 C3 p4 e
+ r/ m( M. ^8 L4 a& s6 \+ Z' [
$ }( O9 ~2 ^ i7 T支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:
2 G N1 V4 r m$ i/ h. R - def __init__(self, block_size, num_blocks):
- o/ j1 F. C3 C3 p* q- d+ e) x - self.block_size = block_size
8 V! I( u: a" O" N3 G0 v- C/ o - self.data = bytearray(block_size * num_blocks)- S, H3 R @) B3 R' q8 R
- 9 V/ _" t# U% o |, h L+ _/ @
- def readblocks(self, block_num, buf, offset=0):
+ Y* x1 L% D' G" K; V- M* e& `% u3 ` - addr = block_num * self.block_size + offset4 \; _8 \% c' q T! c
- for i in range(len(buf)):
" \) i4 t; }* q& `5 r/ j$ W - buf[i] = self.data[addr + i]
* }% o. P6 j6 z1 j! \2 b
3 m! c' U* n2 c7 e0 @8 Q/ n# f4 n' R- def writeblocks(self, block_num, buf, offset=None):0 B" t7 M2 u! |& @7 O5 a4 A
- if offset is None:
/ K4 F, `# L( [! v - # do erase, then write, F! C1 E `: h* o$ O
- for i in range(len(buf) // self.block_size):- ]7 k) U% ?$ g( ]* q' T- Y
- self.ioctl(6, block_num + i)
9 z) V8 l3 W7 x3 B3 {& l. d - offset = 0
2 m6 {) v" `4 S( a. T8 N' P - addr = block_num * self.block_size + offset! z4 y" `+ F# A* R
- for i in range(len(buf)):4 L- w4 |" O8 _# `
- self.data[addr + i] = buf[i]. U2 ~( R2 s% Y1 ~, b4 K) f/ [7 c7 @
% g9 n5 ]! f$ y9 r3 X0 K9 F- def ioctl(self, op, arg):9 W2 N# M6 i# A! P
- if op == 4: # block count+ @# S% Z, k0 y9 I7 X
- return len(self.data) // self.block_size; M4 H- R% s5 n, C
- if op == 5: # block size/ V& W. h* K9 ~ u+ {
- return self.block_size
$ u+ P! W* ^- N& I" v. g - if op == 6: # block erase1 _8 l- @5 Q e5 ?0 N
- return 0
复制代码
: T: {5 H7 ?% S* I( i! K1 @; G! c/ ^+ B5 u
- X% m7 e* C1 Q8 q( |" n由于它支持扩展接口,因此可以用于littlefs: - import os0 B2 S; e6 f7 z- T5 E
: k% r* L* C+ C3 m! g- bdev = RAMBlockDev(512, 50)$ V$ V4 W( [" x6 K" j, D, f
- os.VfsLfs2.mkfs(bdev)2 s/ s3 @; Y. ?2 |, |
- os.mount(bdev, '/ramdisk')
复制代码
2 f; \9 o2 P) C- g6 v( @" M
# A* R* o* n( P/ }, D- z/ W# U" w" U- ]
一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:
) G$ k/ |/ f1 p: z/ [: b# E0 z) ~1 E - f.write('Hello world')
6 R$ Q$ J! V" f% ~, I: M - print(open('/ramdisk/hello.txt').read())
复制代码
9 T$ r; {8 J$ o1 M) N- H! E
1 k u, ]4 L W3 K3 M
2 B9 d0 [" I+ j* V* b7 Y! S; a$ e4 n* V! h4 q0 W" s( F! n! c
: E7 P0 w6 c6 D+ `
文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。 9 ?/ g. B( i/ ], Q: v
FATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP32+ x/ w5 P5 \: `+ V
- import os
( M! U) O4 w1 r& _. x* } - os.umount('/')
( w; h; l: [! L4 e: W# W+ V$ B - os.VfsFat.mkfs(bdev)
. @: D; u7 s! h9 R6 m/ p0 v - os.mount(bdev, '/')
2 b7 p, E$ T" h* j) [. S g
; }! |* ~# O# o- I1 |- # STM32
0 H5 n& J2 B M4 G - import os, pyb, p1 p6 d3 @# v
- os.umount('/flash')
7 z! A/ j0 X3 G' v2 s - os.VfsFat.mkfs(pyb.Flash(start=0))9 _8 c& j5 O* {& s: n1 h
- os.mount(pyb.Flash(start=0), '/flash')
$ w, _3 P0 F/ N7 ^& V8 G1 g - os.chdir('/flash')
复制代码
' I+ V' o2 G" ?$ @
" p1 {& j+ V( Y- J+ _. b1 t! N. ^$ X5 ?2 K& Q S
: g4 H3 g: S7 ?LittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295. : Q z: W" T% ?3 P4 |% Z' v
注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP323 U) d6 L% B) G3 t: d, x
- import os! C% z3 j4 J, N4 ^9 o. w+ M
- os.umount('/')
5 y @0 |6 k5 V0 h1 d k1 | - os.VfsLfs2.mkfs(bdev)
3 ]- t/ }/ q9 d, K2 h% P$ K - os.mount(bdev, '/')
; Z/ x7 h. f9 D0 m2 o( R4 j/ |
( J9 ?; W( c2 I& a! K; z- # STM32
* h! \! f0 I4 |, Y9 O - import os, pyb7 P. _' N3 r! ~% X
- os.umount('/flash')' D j- `3 X. K" j) o4 K5 x
- os.VfsLfs2.mkfs(pyb.Flash(start=0))
5 k3 L' w( G Z j; ?+ B: V - os.mount(pyb.Flash(start=0), '/flash')
2 B6 h( { Z! h: K/ A& p: E: ] - os.chdir('/flash')
复制代码
9 d7 D v+ d8 Y) c; y
- K2 q4 U q+ D7 J+ z7 ^: q6 `
! I. T- a! J# j! C4 Q8 x; `2 M. E6 }7 a) f2 L
混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb
1 A, g: ~8 f- f, F/ ], \3 B L4 f - os.umount('/flash')" V* m) E5 H& b: {; _4 Y1 a
- p1 = pyb.Flash(start=0, len=256*1024) V& Y1 m1 |) {0 `6 w- e4 D4 X3 ^% E
- p2 = pyb.Flash(start=256*1024)
/ b v% N( G/ h" ]7 `( N7 t - os.VfsFat.mkfs(p1)* B6 v' p# Y- B) }
- os.VfsLfs2.mkfs(p2)
, |+ G4 b C2 M! r/ ~! q - os.mount(p1, '/flash')
3 X* N1 Y* |- y# u9 b - os.mount(p2, '/data')) W8 N" v( N/ R* S: }6 C& V
- os.chdir('/flash')
复制代码
* y# i2 l/ g5 Z+ P5 d4 R: _2 N G, d7 {2 c
2 f5 I& v4 A) Y2 B+ k$ x* ~- V4 N这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb
3 I0 Y3 f2 ?3 W) p* j0 U - p2 = pyb.Flash(start=256*1024)2 W6 f& ^0 ^# Y
- os.mount(p2, '/data')
复制代码 8 T+ L3 a# a& ~0 v
( V ?9 G0 x* Y) e$ e; K- m
/ \$ R. {% ^. X3 G8 ^& g) [; O4 S来 boot.py挂载数据分区。 * Z! k+ O0 x& v3 q X) `0 C
混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os
m- ]! q" A- k - p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo'): i% a! ]* a- ?3 r, g! V: S# n
- os.mount(p, '/foo')
复制代码
" `% A) j Y" e: o7 y/ @2 |1 W3 Q# W2 ~1 P- d& T) r& z
2 U9 b) K) Z3 S
4 C8 D6 ?" @0 A: y! y$ c! M, V
2 b; @" I+ P8 g, U5 J3 M' W/ ?4 Z0 v0 M7 d3 p8 H
|