使用文件系统 内容 使用文件系统
8 b. P7 |5 L" Q2 p5 f虚拟FS 块设备 9 E& t: P, ~+ u/ D0 E% O/ ?6 B
内置块设备 3 o, J- F$ D6 E* F
自定义块设备
; X6 h5 h. m( r! @6 h7 }. }
文件系统
7 A1 g+ r( j, |7 V1 H5 }
1 F- }; p- E: K& }$ l5 M' o: Z* D
_& z4 a3 I( f6 v% j . x8 O( D# f6 G- F$ s/ N! m9 @
本教程介绍 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 上,主文件系统挂载在 /。 ; M- n- m3 ?# F U: u' Q$ K3 t
块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。 & d+ I1 s; S9 k+ B' ]
ESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。
, L+ [5 J+ U3 d) c0 bESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。
4 I; r- b4 c# N
% {0 _ z, X4 W; V自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:
, n: w& Z9 V3 I) }: E - def __init__(self, block_size, num_blocks):
% j9 j% F! j+ n: I1 O: V - self.block_size = block_size- R9 @- e/ d% i+ M+ \! z+ ?
- self.data = bytearray(block_size * num_blocks)
" g4 m' x" l8 w4 T- h! _
; A1 e6 B0 C y6 H- o+ k/ C- def readblocks(self, block_num, buf):
8 O @( {, Y: W* r8 ~ - for i in range(len(buf)):2 F! G- i" u: B. D. d# |
- buf[i] = self.data[block_num * self.block_size + i]5 J+ \6 z! G1 Y7 Q6 A
- 5 [' o6 F8 W. a3 c6 n+ D) h( N
- def writeblocks(self, block_num, buf):. X. d% H/ {/ u5 } o/ i& N
- for i in range(len(buf)):
. W. x6 \# t6 q* I( j - self.data[block_num * self.block_size + i] = buf[i]' d7 D8 O" B( N
- ) x1 B. x: F: n$ r. n
- def ioctl(self, op, arg):/ @; X4 Q. ^" b" D* t
- if op == 4: # get number of blocks' ~4 G" F6 O4 A0 z: L, O; T+ L& L0 d
- return len(self.data) // self.block_size0 r! r( ^# B0 V X, V: w: _7 Q
- if op == 5: # get block size
0 G( z. m- z( o - return self.block_size
复制代码 $ m8 ^4 d2 ^+ G
! ]/ ?7 }: b( f2 E. O: A) ^( `( e# }0 b( c
它可以按如下方式使用: - import os6 [' m' k) M* x$ b% b- p
- 2 l6 |; q' ]1 m$ q0 X: o
- bdev = RAMBlockDev(512, 50)# T/ ~5 W5 E5 J
- os.VfsFat.mkfs(bdev)9 c! s0 ~, E' ^* T
- os.mount(bdev, '/ramdisk')
复制代码 ! w7 s4 X9 j, w/ M {% y
) X# W$ H/ g9 t/ C; R
5 m; d+ v4 i& O' B# y5 \8 Q# p
支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:
! H c' o. z% S/ H' g$ c! H - def __init__(self, block_size, num_blocks):
/ v# S+ D, X3 U/ ]/ b - self.block_size = block_size
% i$ g; M6 ?% |9 M5 I" `4 ]5 V - self.data = bytearray(block_size * num_blocks)
3 ~3 {6 a7 X) S) n# s# h N3 ~ - ) ~% d, D9 Z' |0 b! d8 d
- def readblocks(self, block_num, buf, offset=0):8 P: e3 R/ B! q$ ^9 z* ^! r
- addr = block_num * self.block_size + offset" x- W; k+ \/ @/ j
- for i in range(len(buf)):# c6 n1 w2 s( G. |( \
- buf[i] = self.data[addr + i]
6 Q2 W4 W1 e1 {. l0 s - ' f( R2 K2 o' Z( W) X: Y
- def writeblocks(self, block_num, buf, offset=None):/ P8 |- m9 {! v! H6 y
- if offset is None:
2 J' _! Z1 Y M( y - # do erase, then write9 e1 H# V5 }- x3 E- ?+ \5 W
- for i in range(len(buf) // self.block_size):, r8 n: q& k: \5 Q
- self.ioctl(6, block_num + i)
" y9 g; w* Q/ q% Y1 ` - offset = 00 p3 ?' y8 k8 r9 e0 c
- addr = block_num * self.block_size + offset
1 x: o) Z/ k! o$ d s- O - for i in range(len(buf)):" r7 d$ L, ?4 K2 d* h
- self.data[addr + i] = buf[i]
: [: I8 M4 s9 `7 Y p" s
5 Q% K" V* g3 L9 M& D0 w2 R- def ioctl(self, op, arg):
* Z$ q1 U0 `# d8 Y8 a8 V - if op == 4: # block count( L* J/ x! Q, s$ I) b; t V, ~
- return len(self.data) // self.block_size
' e0 a4 A& M' L- H# h* R4 r - if op == 5: # block size- g8 o7 z- ^2 o- q6 c
- return self.block_size
' Z/ C9 s) O, b7 @4 t2 d - if op == 6: # block erase
' }3 v$ k3 |8 G9 M - return 0
复制代码 # x: \+ Z1 U0 Q. A" z! d$ p7 A4 m
: R* _1 B/ K9 T; ?
+ l) w. l+ V4 G4 ?6 B. M由于它支持扩展接口,因此可以用于littlefs: - import os
+ N4 e$ f( S0 r+ w
6 v% V* U- ^. Z0 Q% t8 h w- bdev = RAMBlockDev(512, 50)0 @- {/ `: P' M% G4 B! x
- os.VfsLfs2.mkfs(bdev)
" e/ `4 C6 V' { - os.mount(bdev, '/ramdisk')
复制代码
% q+ y. q# p9 `& b# e. H* y( ]8 e7 S0 X$ w8 T( G
+ J% }5 a0 X( `: y+ \2 ~& f* [; d
一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:
- z7 U2 }6 j8 E1 ]: l9 E. l. d - f.write('Hello world')# ?1 g8 k. \' @
- print(open('/ramdisk/hello.txt').read())
复制代码 0 ]- C( D: [" l1 p
: e$ t3 a# }9 z* a2 U8 l. z9 e
[: H, K: P( Q1 e T( F0 Y0 ?7 q, e' Q z
+ M% `+ p7 }, Z文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。
* K. M2 \9 }2 m$ u$ [7 p5 uFATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP32
, t7 f& T! N, h3 y8 p - import os) S7 O$ V0 j* d3 }
- os.umount('/')3 m# P" r# S$ x/ `$ G, }
- os.VfsFat.mkfs(bdev) e7 |- s0 T. B( R, O Y3 @+ D. O' D
- os.mount(bdev, '/')* I( C8 Y* ?# o& g
0 J1 L9 `* y* t$ c6 K: y5 B- # STM32% p; P- e+ m/ U. s& y
- import os, pyb3 Z/ G7 G% s6 ]4 d7 b- o
- os.umount('/flash')
2 |& d+ K9 k$ } - os.VfsFat.mkfs(pyb.Flash(start=0))
' [! L& M) Z8 K - os.mount(pyb.Flash(start=0), '/flash')
; {) o# G% D) ]- }& C4 a - os.chdir('/flash')
复制代码 5 j! M* o2 H+ G7 X) [9 S2 E, D
4 Q: l' y( h0 k5 W* ]
; R P2 R, y! S# E& F9 j7 l, ^+ F+ x" A; N& B% M
LittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295.
7 X: d' } M! G% v注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP32
* `& S- v. Z8 S9 ~ - import os# R6 ~" S. }- v+ ~0 ?9 C. |+ v7 m$ G
- os.umount('/')* t7 s p. D, T! k h
- os.VfsLfs2.mkfs(bdev)
/ U* @# q6 k. g1 z4 b3 ?0 k - os.mount(bdev, '/')% ? q" p3 J Z* ~ O, G
4 G* u) C3 S# W& m. G2 G0 G- # STM32 N% h( |5 A$ x, e
- import os, pyb
/ j8 P8 I v0 J8 O0 F* _ - os.umount('/flash')
: s7 l4 a8 F% @* j: o- e0 t0 z - os.VfsLfs2.mkfs(pyb.Flash(start=0)), o q- d' S: r) A1 ^' y# ~
- os.mount(pyb.Flash(start=0), '/flash')
. I3 V$ X. q5 Z1 u- y* C# f8 d% Z2 h' z - os.chdir('/flash')
复制代码 5 Y4 Y0 Q" [4 {) b
6 C& ?2 f$ `$ l
% p2 d! }# {% l6 s4 k+ C
2 G4 M+ }' {. x9 u8 }/ H. Y; ?& C混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb) m4 p5 O1 V, \# A6 C& t& `$ [" n
- os.umount('/flash')
* q9 u$ G# U0 `0 t# Z7 D. Z - p1 = pyb.Flash(start=0, len=256*1024)
1 t' A: n9 `, p: o+ d - p2 = pyb.Flash(start=256*1024)+ O" N5 g7 R# p+ {# N
- os.VfsFat.mkfs(p1)
; C0 @, b, V d* ]1 {; [$ p6 \ - os.VfsLfs2.mkfs(p2)
6 g( e& b% M# k2 R5 A( u7 N0 Z - os.mount(p1, '/flash')$ ~4 N* f# d4 g6 }$ E
- os.mount(p2, '/data')
( q& u R9 t& ]( b6 n - os.chdir('/flash')
复制代码
0 r: g' I- e* X( ^- [
6 ]* s C7 x0 l. X4 r# b& k4 I$ E. ~4 s+ N$ U
这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb3 w& x- a4 Q1 K2 X
- p2 = pyb.Flash(start=256*1024)
( @6 Y- b/ w$ A7 d) H3 u7 P7 f - os.mount(p2, '/data')
复制代码
8 T2 K% P6 ^9 |' H# p0 d' r. {/ S! v6 L4 P1 e7 n- R
B* k n& m' ?3 x
来 boot.py挂载数据分区。 3 |: E7 b0 Y# {# D8 W
混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os, z; w5 g6 I5 m6 L2 ~: ]2 o3 e
- p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')6 c" w w( S$ f( f/ M- U% Z
- os.mount(p, '/foo')
复制代码
2 e: l2 L$ i1 B" X' a" f( i! S) d$ |
8 W; ^! H5 ?5 s$ y% R8 [; E+ b4 V8 X
9 |/ a- F% g; Q0 I b* V+ Z4 E7 q/ [1 y5 A8 j( V0 I
% l$ g1 c, x* Z* }9 Y- u% b# X0 l' B
|