使用文件系统 内容 使用文件系统 ( C/ y- x4 _6 [/ Y1 }" x) R b+ V
虚拟FS 块设备 0 W4 k: h$ k& R
内置块设备 8 S- ?1 P2 T$ u: K- G* V( a+ ~5 P
自定义块设备
% S" M* h- K! J8 `/ v
文件系统 # E2 U/ D+ I _1 j: L% @+ v# O
" X, `' L7 X) A3 ^& T
! q6 A; l2 P" _9 ~$ v 0 ^. k6 `5 A* _+ {; X* v' V; e0 `
本教程介绍 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 上,主文件系统挂载在 /。 ; E! R% R3 l9 S- R1 q5 |1 V
块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。
; P1 z6 A: D0 h HESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。 ' }9 H! w, v0 M7 q3 E# ~& ?7 @. o
ESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。 6 g5 `, _' k- k* v+ {- w
) e* t4 J# I/ w- `; p) y7 e
自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:& R$ V# m: ] F
- def __init__(self, block_size, num_blocks):
( Y/ H' g: W+ d3 R( L - self.block_size = block_size
, |! R( e9 g/ k6 ?* E( T - self.data = bytearray(block_size * num_blocks)) H# g p% E5 e* N# k, z" r: l
- , \9 n, t& s/ f. J' |
- def readblocks(self, block_num, buf):
/ _8 [/ k7 q6 `- W2 [ - for i in range(len(buf)):
" O d; T# t/ W2 Y5 a0 R b - buf[i] = self.data[block_num * self.block_size + i]7 b9 _; g2 C" a! u5 g2 ^- T1 j! u
! _/ a' S% E+ g9 O- def writeblocks(self, block_num, buf):
6 U# g9 C/ {' t3 ^) L - for i in range(len(buf)):
& f9 a0 j6 R: V. W' ` - self.data[block_num * self.block_size + i] = buf[i]
( t/ I h1 o4 M% k - ' S3 e4 E& Z' y2 J! i3 { P
- def ioctl(self, op, arg):7 b- Y7 Q$ E0 ~# C* S* y9 c
- if op == 4: # get number of blocks+ R3 y0 U! P5 {. ]+ ?
- return len(self.data) // self.block_size v9 |/ K+ ^6 G4 A# g- N
- if op == 5: # get block size9 Q7 X' s) d- i, |' o* l
- return self.block_size
复制代码 & `; C' z6 D _9 j5 I: w% A9 b
5 `( |' ?% b4 e1 u5 q3 H; a& v0 y# u1 D& y" n. p
它可以按如下方式使用: - import os
% C7 [. R6 D8 U: m7 E. \! Y. h0 n
' D& x" }' ~7 F N9 D& J7 }: u- o- bdev = RAMBlockDev(512, 50)
; E/ x# \. }$ M) i) V: v: H' C. b - os.VfsFat.mkfs(bdev) L( U: \' ]+ Q# ] @
- os.mount(bdev, '/ramdisk')
复制代码
1 } J. [6 u: q0 K+ Z) k J9 _9 ~0 z2 U! [) t. C5 Y0 R! {. `
$ u% \7 t8 B# U$ ~1 `5 U, @
支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:+ H- [7 I1 o! W
- def __init__(self, block_size, num_blocks):
) ]' p# U7 i1 Y/ b9 \ - self.block_size = block_size
; z3 q7 P4 K j! g% u' h) ~" l0 ` - self.data = bytearray(block_size * num_blocks)
6 v& p. Y( \7 B1 |/ r; G
7 P) z+ ?+ T8 v/ y# `" x- def readblocks(self, block_num, buf, offset=0):. V& Z4 f8 @6 @5 t
- addr = block_num * self.block_size + offset
" p3 G. G' _2 C9 A+ y% [8 n6 m - for i in range(len(buf)):9 h) C# b9 m5 b4 j
- buf[i] = self.data[addr + i]# Q7 {, a% e; J) x, P: t3 J
- 6 L1 Z0 B) w. K. b
- def writeblocks(self, block_num, buf, offset=None):
$ }5 S9 u4 o" P9 }. B9 D- d - if offset is None:
& i9 {8 Q- m- b4 p - # do erase, then write
# q, M7 K( e/ b% A6 L: h - for i in range(len(buf) // self.block_size):1 j1 z1 G* _3 c* k* J4 [! j5 r
- self.ioctl(6, block_num + i)
/ z5 v( \" J- J; V, q) t } - offset = 09 _7 d" J" l% n: h- l/ d
- addr = block_num * self.block_size + offset
( f0 }3 @) y! d2 j9 G5 [ - for i in range(len(buf)):
; q9 r( j7 P& a4 H; x' a - self.data[addr + i] = buf[i]
/ f8 M$ @ ^# E6 r: `, z
" ?# }: b) `' x* p+ S" X- def ioctl(self, op, arg):" p/ \! M( v" h. }
- if op == 4: # block count8 z/ H$ g) i5 q( x
- return len(self.data) // self.block_size7 j6 T$ G+ F/ M. Z5 G( ]- K! L
- if op == 5: # block size
, s* N: @: p- G( d2 y0 d - return self.block_size$ J2 {: p8 r7 \" `( ?
- if op == 6: # block erase
6 q! A* M1 z+ M( o: X. d: x2 w2 E - return 0
复制代码
; u2 v! a! z m6 i/ |$ D. p7 x* S' l# u6 ]5 |. T
2 i* u) y+ k& S" W. F2 P4 H由于它支持扩展接口,因此可以用于littlefs: - import os) s( T& _9 Q5 M# I5 q* T: `- r
- # x9 Y$ u Y# F2 z; {7 d
- bdev = RAMBlockDev(512, 50)( r0 u# D$ h2 z* g
- os.VfsLfs2.mkfs(bdev)
+ i) }3 T" d3 l1 \, V1 z - os.mount(bdev, '/ramdisk')
复制代码
* g5 X+ Y. @+ L6 o. @! w8 L$ l1 r4 c
% P0 B% ~+ S- {# M: Z X8 B
8 q: t0 X" q W4 \) M$ I+ s9 U一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:
* K/ c" G0 a" J$ } - f.write('Hello world')( \1 T4 ?. Z$ H1 ?+ m
- print(open('/ramdisk/hello.txt').read())
复制代码
6 E+ p- g. O6 r" F& i
2 S5 ]$ `/ e* q$ j% ?3 T
, n5 Z0 h) k' r; v$ {: [2 F) ~' P0 z) Q( Z% Z/ i4 L
3 U4 {3 E) |; m: d文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。
9 [/ c8 ?2 Y3 y+ F& a0 g, KFATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP32
' o/ `" |* U. F- f, L - import os
( e4 \6 `0 P6 A" d" n; g4 J - os.umount('/')
! p# @! p. D& ` - os.VfsFat.mkfs(bdev)) H& W9 i; S' i" _6 l
- os.mount(bdev, '/')
6 @2 T3 A7 L" D
6 z3 i! y9 k3 G; A- # STM32) K" y" o) o- T; V4 i
- import os, pyb) o [- J* `7 d* [0 M# S7 o5 ~4 `
- os.umount('/flash')
, @, J+ [" U# v# V1 k - os.VfsFat.mkfs(pyb.Flash(start=0))
" R! M& X5 |" }+ ~4 N( w) D1 @ - os.mount(pyb.Flash(start=0), '/flash')
4 {8 u* m8 I/ s) |( v% z5 q1 U - os.chdir('/flash')
复制代码 ; R! L/ i& l) {3 d% |
$ R- w2 a' V s+ V, s
: _6 B0 Q; f5 ]# F
2 }1 @# Y2 K5 g& i9 p2 ^3 pLittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295.
: @8 c, ?: I4 Q+ l6 s9 w注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP325 O4 B: X7 q& T3 O# c' x3 l
- import os
2 S0 T9 j+ V; _; R% E" p0 z/ c% g4 ? - os.umount('/'), v* H- o7 h2 D3 ?* I0 U: I
- os.VfsLfs2.mkfs(bdev)
1 j% Z- n, A) n& w( \* S% ~$ } - os.mount(bdev, '/')
& R1 L/ i! e& m. h
e4 \6 Z1 E& s3 V, ~6 t- # STM323 }' z/ f# B8 p
- import os, pyb
7 c: z2 {; v9 d' K - os.umount('/flash')4 I3 F; Q* g; B& j5 t
- os.VfsLfs2.mkfs(pyb.Flash(start=0)) r: b' {/ R4 Y" N- J4 ?
- os.mount(pyb.Flash(start=0), '/flash')
1 ]* Y. }0 E7 O! w - os.chdir('/flash')
复制代码 * A* C8 Z/ y% P& o( T: I
( Q% I) r( O0 P
7 x7 @% l8 j6 n. T- n# ^0 p7 k2 |+ n% K7 c
5 u e. h7 M& ^7 f混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb9 o: O* w3 H" a3 J T1 B$ x6 f
- os.umount('/flash')
" t4 T5 {& ` ?1 y- g: ]1 d - p1 = pyb.Flash(start=0, len=256*1024): @9 u" v) B: `! }4 x; f W) d
- p2 = pyb.Flash(start=256*1024)
# s9 Q' M% B7 l# Y' X( A - os.VfsFat.mkfs(p1)6 M0 W) ]/ D# ]+ V
- os.VfsLfs2.mkfs(p2)/ A3 n4 w, d# p, K; P
- os.mount(p1, '/flash')
' I; n+ |$ K2 f/ n1 Y7 @+ N: p& | - os.mount(p2, '/data')
3 S5 A6 a5 }9 N! n3 B8 f - os.chdir('/flash')
复制代码 . B% g1 v, z" H8 o7 ~) m! n6 {
* f6 S0 N0 D, J
& [' g' W% d% h- e H: Y9 }这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb, ^2 n: k1 G! D( l0 P4 K5 Z) U
- p2 = pyb.Flash(start=256*1024)
- T8 c, r s; ? - os.mount(p2, '/data')
复制代码
0 F# e( A% M1 m
& n# o; T0 m( i5 A" s) P) Y' C4 j" a. @5 T
来 boot.py挂载数据分区。
. g. s3 x4 p! W" n混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os
+ ^- r9 ] P; `& I3 u: V - p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')
! A! g+ S! U' [. s4 T - os.mount(p, '/foo')
复制代码 4 `; Q( @! R4 F: w) n# z
& B. C3 h% K% c& B2 b! r9 b4 u( {8 J! F9 ^# X0 A+ `
+ ~* g5 C' t; l3 E
7 T V/ [; D8 u
8 ]) f, A! Y1 d$ A% g
|