使用文件系统 内容 使用文件系统 ! [5 R. B0 E) [( n' N
虚拟FS 块设备 $ d. k3 {& i5 x; \
内置块设备 2 m$ V, g& o; U3 i- [0 o
自定义块设备 6 B7 a! Q5 t3 t3 g2 R5 _/ M2 e7 @
文件系统 # Z: a8 U0 f @' s7 S8 T
- B7 q& V* q' t% u; j2 |
1 u" }" B; I" H: r
* Q+ {& O( b3 g8 h% _) 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 上,主文件系统挂载在 /。 $ i- }, G! C8 R) A+ T" p% t- }
块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。 X) s" w8 G' c; w2 W& n7 J
ESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。
" F+ C8 B; W4 F: OESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。 o, s' r( f8 }( X
, u% ^+ G, | W
自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:8 N6 l7 I2 s' W" F% F' D' q
- def __init__(self, block_size, num_blocks):
' ]0 m' n. r' F3 t, b - self.block_size = block_size
: S: N# l4 A; @2 t7 n, t - self.data = bytearray(block_size * num_blocks), o- p) `, w* M, X5 B* p
- 1 Q+ ~3 I! A/ v! W; M
- def readblocks(self, block_num, buf):
7 y) Q3 W/ m% K# p2 q' z - for i in range(len(buf)):
9 d6 z* l! q" p* T - buf[i] = self.data[block_num * self.block_size + i]& |0 V4 e& z7 m: [8 }
1 [% v. k0 z+ y- def writeblocks(self, block_num, buf): v& v1 r" H3 Y x( x1 f
- for i in range(len(buf)):+ \8 W4 S4 }- _2 n, Z! F* p
- self.data[block_num * self.block_size + i] = buf[i]
: }. c4 y) q: g0 |& Q, V
& }$ q& H) }. Y0 c2 Z( ~! j- def ioctl(self, op, arg):
+ q0 r A. H# \+ ?8 _! k - if op == 4: # get number of blocks4 o3 ?5 T. r p, j
- return len(self.data) // self.block_size, }8 D7 G8 [* d( P. I$ Q( ]
- if op == 5: # get block size w. q$ n; J% k+ Y7 F8 ~# i
- return self.block_size
复制代码
* ~ h# v' K; k: Y1 S$ b( f& s0 n) C }( C; q
) B- I7 h4 ~6 \- w: V它可以按如下方式使用: - import os% h* |8 u/ _3 p5 ]( ^
9 K9 W7 o0 Q8 b0 v9 B9 }8 A% V- bdev = RAMBlockDev(512, 50)3 i9 c0 T$ w- w; q d
- os.VfsFat.mkfs(bdev)9 y P' I; U4 a, j. h
- os.mount(bdev, '/ramdisk')
复制代码 / g! P9 I. S' A
( p. r3 j& m3 `' ^/ V5 H$ K l, H: X
3 `6 }! Y% H/ q5 B" n
支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:
/ i4 h: R; m1 k, D! i" S" Q - def __init__(self, block_size, num_blocks):
0 `8 e) y( @4 @) ]8 L0 f5 \+ G - self.block_size = block_size a6 X; A9 B, W: Z2 a: Q
- self.data = bytearray(block_size * num_blocks)$ W8 P3 F: x. r8 T8 D+ p/ N9 z8 \
- 9 L+ U/ N0 _) a' A
- def readblocks(self, block_num, buf, offset=0):
6 `' M. @) n# `/ M - addr = block_num * self.block_size + offset- d" s' i. A4 W- G9 r) h/ {
- for i in range(len(buf)):
9 z* p/ |% z; J5 f7 }: D - buf[i] = self.data[addr + i]. E4 ?" \1 o: y. r! P; M2 p
: _* A9 G/ B; I- def writeblocks(self, block_num, buf, offset=None):& f! ]# _% c K% \3 } j6 b8 B' s& R
- if offset is None:
3 X$ {0 W8 V' n1 |- g; K$ X6 ^ - # do erase, then write7 G \, w) O A1 N/ E/ @( ]
- for i in range(len(buf) // self.block_size):$ O M/ `/ _" M: D, o' L) P& y7 T2 R! E
- self.ioctl(6, block_num + i)1 h. S. j, H. V+ V9 S# J& R q
- offset = 0: ]# }5 O' ^2 a5 R! G
- addr = block_num * self.block_size + offset
9 a2 {9 Z: ^) `' F) s- D$ s - for i in range(len(buf)):
- _4 m1 I* N% o u4 t - self.data[addr + i] = buf[i]. e8 P T8 u+ r9 E
, r1 G8 R; A, D- def ioctl(self, op, arg):
0 D: o0 ?. g& t) w6 |! L - if op == 4: # block count9 l7 R) F: V* B" N
- return len(self.data) // self.block_size
/ Q) H' W6 @% M - if op == 5: # block size3 |4 b$ r# O$ i4 x
- return self.block_size4 Y* [8 M# d8 ]3 D9 a2 M+ y8 A
- if op == 6: # block erase% C5 \* c2 O c6 X
- return 0
复制代码 / m6 ~8 X; ?" Z" J) D9 G
5 ~) s8 h9 Q- G& h x" H T
8 u, v: _, B; F. b- P6 F. C! M由于它支持扩展接口,因此可以用于littlefs: - import os
, K; S4 O; m, a' l- @
. P- A6 o5 q: d2 \/ P- bdev = RAMBlockDev(512, 50)' i0 o2 E8 z7 G: l+ L: x# i
- os.VfsLfs2.mkfs(bdev)" |% N' [: n4 ^7 }: N6 j3 h% G
- os.mount(bdev, '/ramdisk')
复制代码
- Y% F" y; W- K& ^+ m# N+ |* c' j/ U- V6 p8 ?* {
6 E% M4 \/ g+ r8 ~' X/ i# J6 O
一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:
. a' l: k; W5 a - f.write('Hello world')
0 E- B n- _2 H0 X, ~ - print(open('/ramdisk/hello.txt').read())
复制代码
: W, S: p8 B# N3 V/ y9 }* L' Q1 V* K" l% `
5 ]9 p! l7 Q0 m, k* r4 C6 t( j5 w! I( `! H: k6 z2 h- d# v" J, ?/ S
6 c! e/ w9 v; J; h
文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。
8 d' g" p+ m* K/ b& AFATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP32" x! v% J1 _3 _7 `) \8 v9 O( {
- import os
: g1 U; ]& a/ n } - os.umount('/')" D& ]3 f; R$ L
- os.VfsFat.mkfs(bdev)
, c/ \6 t' X" B3 B3 y5 E2 m - os.mount(bdev, '/')# [* H: C8 W; J9 @# D4 I- P
9 w* G9 f! I) ]! r- # STM32
% d- h( e2 S! Y) } - import os, pyb9 Y/ M4 j7 `( {+ q# P
- os.umount('/flash')
2 m |( d. o% a: q+ Y( S, } - os.VfsFat.mkfs(pyb.Flash(start=0))
! T- Z* t' _) F9 Y/ i9 H9 S6 b - os.mount(pyb.Flash(start=0), '/flash')% ?2 _# b* E% P+ G* h7 r
- os.chdir('/flash')
复制代码 * L) L- M" E: w- U9 _0 H8 J" J
' _ c t2 I2 T$ _
1 j" @5 k& b* f: ^. X- g6 c5 z/ u. b, J3 A& r3 Q
LittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295.
! G \( g: T& e注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP32& |. H+ d$ {% T" H/ |
- import os
# g% V4 k# ?* D; w" T - os.umount('/')
% `- Z- k- r& J' p2 g - os.VfsLfs2.mkfs(bdev)9 @( w$ N6 Y' _& k4 v
- os.mount(bdev, '/')" d4 L$ E" @& J9 j
- . U' P1 m F( c" Y& K0 z
- # STM32* g7 b- V& N8 K' N v2 S2 `8 u
- import os, pyb- O0 q" v9 R0 R3 W2 ~
- os.umount('/flash')
/ _4 H/ c% P) u6 X# V - os.VfsLfs2.mkfs(pyb.Flash(start=0))" I( {+ S% D5 ^- I) T! r
- os.mount(pyb.Flash(start=0), '/flash')4 h$ y: y1 ~: \& f# O! P: w
- os.chdir('/flash')
复制代码 7 q6 f8 O5 }; Z o! N) U
9 O6 T9 u% ?+ d- X
5 O3 z0 t* ]* g
/ [- V1 C; G1 i! h& O l& N
混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb
1 n3 Z. T9 r/ M4 a - os.umount('/flash')" s7 m( O% Z* {3 Q9 G
- p1 = pyb.Flash(start=0, len=256*1024)# w$ A, w8 ^" P1 z5 ]9 M6 n+ \% I
- p2 = pyb.Flash(start=256*1024); d7 T* Z5 I6 z9 j
- os.VfsFat.mkfs(p1)
. b3 g& {& t4 w% R% k - os.VfsLfs2.mkfs(p2)) ]3 Q! u: X' ^6 \/ K& U
- os.mount(p1, '/flash') y% C) G/ k0 F L4 M2 x
- os.mount(p2, '/data')
$ n( W: L9 L4 \, z+ n h k7 b - os.chdir('/flash')
复制代码 1 P% w2 V3 o. Z$ d9 m. X8 r1 d( s* f
+ |1 \+ _" N! P- j! Q
5 [1 z5 U6 A5 a; F& g: M1 w% {5 T这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb
4 }, y2 J0 d8 U& Z+ F U- i - p2 = pyb.Flash(start=256*1024)9 f6 f1 q6 I: G+ f q( G
- os.mount(p2, '/data')
复制代码 7 D! s1 `* [" S- b
# C/ b& T l6 \
" E3 W4 { k* p1 w! z来 boot.py挂载数据分区。 1 |9 ?% `( {9 N ?2 C. P
混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os: }7 M! M% l; K3 {! `' [
- p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo'). l& x: ^/ @. \4 c3 q
- os.mount(p, '/foo')
复制代码
& Z7 d9 M2 y: W! m3 i8 B8 b
0 q5 h/ u) f8 Y2 x8 y) j5 M2 \+ \+ e+ g& M( O. J
0 A7 B. v3 a- g# ?# c0 w. u8 h7 G6 s" ~( a6 @$ R* e! I5 f
6 b( a! x9 w% s, o4 O& Q) a) [/ m' j |