使用文件系统 内容 使用文件系统
5 N$ r* F8 ^/ F* |! |7 B: x虚拟FS 块设备
2 {" o6 K* A) h* z内置块设备 ( s. q% _3 H/ a: Z5 B0 N8 E, G
自定义块设备 6 h( k) I. X( G$ Z; m
文件系统
) V2 w {. a0 q" G: f% C, x1 T- e- v1 }7 R, E% j
2 s" _' J# t" K4 e- ~! \
0 d# Y- q5 `* e! _3 w' c本教程介绍 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 上,主文件系统挂载在 /。
4 K6 T( t7 q! x' W9 N块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。 Q2 [9 s$ ~) x a
ESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。 9 |/ x# r# J% s/ U
ESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。 " y) I* s& u* h( ]1 Z! A4 ]/ _3 y
1 S, D) ]* u3 b& p自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:
! _/ a" E$ d6 ^& g+ E- A - def __init__(self, block_size, num_blocks): ~$ w+ g. ~) n4 S( l' P( d6 h
- self.block_size = block_size; z4 `- j: W6 q5 q3 H
- self.data = bytearray(block_size * num_blocks); e i# @! X4 p; H, q1 p' `3 X8 R
e& S8 v- Q' M s- def readblocks(self, block_num, buf):
2 i; V2 @: P' v' ?$ z" u4 {% ~; M - for i in range(len(buf)):* [/ G( a* @5 j, V' B
- buf[i] = self.data[block_num * self.block_size + i]
4 r9 D9 e$ T+ y }5 @* c
; r+ k9 I9 F3 b, J+ j3 B5 J- def writeblocks(self, block_num, buf):
0 w: \3 Z9 |. d! [ - for i in range(len(buf)):
3 b& r. y$ w4 C% A5 a. J - self.data[block_num * self.block_size + i] = buf[i]0 J5 _$ b) D5 U; S) w+ W
- $ |* J9 h' C* o7 R( z8 T4 c
- def ioctl(self, op, arg):
) |9 ^0 ~5 _* W0 Z, [: i - if op == 4: # get number of blocks
2 @6 }! ?, J5 y* q! J6 W - return len(self.data) // self.block_size) D3 H6 h& _+ Z, T& Z( I5 n* k& p
- if op == 5: # get block size
0 A3 M! @' [. M1 q2 R. J# } - return self.block_size
复制代码 6 P# I% L* {5 f I2 F
: R9 R. n% _9 I+ @3 H
& m' }& u# i# `" Y; {1 v它可以按如下方式使用: - import os" L$ W5 F& j5 e: w2 J! k
- ( r$ k# Z6 ~5 A1 Q7 F- D
- bdev = RAMBlockDev(512, 50)
/ @+ v7 Q7 J8 u( ^) P' @ - os.VfsFat.mkfs(bdev). a8 M& t! F% E$ \; c$ R
- os.mount(bdev, '/ramdisk')
复制代码 9 ^& g' l7 ]3 ~
. I' h* y' c# @) e3 T
" v0 E* ~: K3 ^+ d* T/ h/ t# I支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:
{2 W* G: c- S - def __init__(self, block_size, num_blocks):9 a0 D1 D8 l9 _
- self.block_size = block_size
5 n7 u5 G/ Y. W( ~ - self.data = bytearray(block_size * num_blocks)$ N( ]2 a& X3 ?) ~6 i$ G* _
- , w; G8 k% f9 `) l, I
- def readblocks(self, block_num, buf, offset=0):" k2 ~6 s1 a& T" g; q
- addr = block_num * self.block_size + offset
& N& U3 K" ^; B& ^" i0 } - for i in range(len(buf)):3 u3 \- E& ~# N/ E
- buf[i] = self.data[addr + i]2 l7 ^5 w6 R/ Q! n1 Y
- & m4 t# J; }& k5 [% \, k7 @
- def writeblocks(self, block_num, buf, offset=None):
8 }% a9 v$ ?$ K0 y, q8 G - if offset is None:
% }- r( I$ d+ | c' g; b. l0 R( T - # do erase, then write; O% v0 q- s( j! T
- for i in range(len(buf) // self.block_size):
% c# n' E2 I% B% }/ B! g - self.ioctl(6, block_num + i)1 V/ {' I2 Z4 t# o! Q$ R6 H' y) s
- offset = 0
8 U5 f' Q! @& R3 l% ?6 i - addr = block_num * self.block_size + offset
) T5 m. z L' B0 l; c/ x* b/ N - for i in range(len(buf)):( {+ x% h# x3 A
- self.data[addr + i] = buf[i] a; G' n: G8 g* s; Q
8 L1 w7 ?3 j' T- def ioctl(self, op, arg):
: L7 ^# Z' o( [) r) Q - if op == 4: # block count
! q, G) G1 a$ r/ B- W6 b - return len(self.data) // self.block_size( W- e _/ z' |8 z, r
- if op == 5: # block size. \& s: V; m5 V2 W
- return self.block_size
5 M7 A& {2 W, w) D$ Z5 o - if op == 6: # block erase
: ?' c+ n8 a; ^8 j: y - return 0
复制代码 1 h/ W) j! I8 Y$ {% P4 g( O
4 U0 {, _) U5 d4 ^- y8 D& |" v
2 y% h6 {+ I7 d! [; F6 Q由于它支持扩展接口,因此可以用于littlefs: - import os
: H: W/ Q0 z3 i1 I" K" K
- t6 ^% }" O3 d; c$ y* H# b. V- bdev = RAMBlockDev(512, 50)
6 j/ p5 K5 `% L0 w6 q5 \, T - os.VfsLfs2.mkfs(bdev)
6 t$ R& a$ U% ^% D/ w& e+ Z - os.mount(bdev, '/ramdisk')
复制代码 . M' S+ C5 a k7 H4 ]
. I# Q7 H" I9 d' N! S y/ \
6 q. |- T, j! O# P8 a一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:% H/ G( _ g$ I, O! X0 w% d$ X
- f.write('Hello world')
& d; ~( g9 Z3 a) C- C6 b7 P - print(open('/ramdisk/hello.txt').read())
复制代码
0 Q7 W! e6 [/ S8 w" B. P7 k' H
. @+ l& {. C9 \ M8 {3 H; C1 P* |% {3 t+ l
' v( |3 m& R: g# g
9 U0 v- w8 I2 [4 I
文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。 . j' u" n( s* i
FATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP323 }2 ?$ p) G2 {7 y9 Q. p
- import os
5 I- F1 g9 z& l. l - os.umount('/')
- O, O3 ]5 C5 {/ B/ X9 S9 w* s5 B* A - os.VfsFat.mkfs(bdev)
; \2 C# w3 Z3 i* t0 |( b1 L - os.mount(bdev, '/')4 [$ b0 |! U7 |7 B5 r' W
6 v/ Q* R' H# M! ~: d ]- # STM32
: B, x: v8 F* U8 {$ v" X* \, k3 H - import os, pyb" x3 P; C6 n$ V6 Y n
- os.umount('/flash')
3 [6 l" D8 n+ R# W5 Y0 g - os.VfsFat.mkfs(pyb.Flash(start=0)), N5 n9 F% Q# k" ]0 u( q7 e
- os.mount(pyb.Flash(start=0), '/flash')
3 `" ]0 @0 F; q1 n1 B. ?5 w& h - os.chdir('/flash')
复制代码
% g6 c3 e# F1 ^) Q9 ^: U- D& ?
/ l7 T, j( H0 f' U
& _! t0 [* H j" h
+ n$ ]8 u" g* z% r( B. sLittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295.
- u9 I0 F5 t" `; P注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP327 u' N) L& h% |: N
- import os& w1 {5 f5 I2 G' T7 ]$ ~! P
- os.umount('/')
+ w5 M' ~6 @# ^: I' Y - os.VfsLfs2.mkfs(bdev); r% N$ h- ~$ a# C- r
- os.mount(bdev, '/'). u5 |3 ]% {8 s9 L; `
5 X) Z! T- y3 q% a! K' @0 z7 g+ Q9 v- # STM32
, u8 X' p X0 d& ^* y - import os, pyb
% `7 n( N" T5 c& B# g4 N - os.umount('/flash')
3 x% \* z2 g" E# A - os.VfsLfs2.mkfs(pyb.Flash(start=0))/ ^+ D8 Z! w3 H+ ~/ q" H* l/ t
- os.mount(pyb.Flash(start=0), '/flash')
0 \( K a# l% w$ a - os.chdir('/flash')
复制代码
; q$ [3 |+ v) e
6 d0 |! O. x' m/ u! n/ F0 Y4 V
$ H6 Y, C8 Z* N2 m
; J) o: y! y7 ^. c混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb
2 ]1 D2 c; A$ u8 {7 \6 k+ l5 ? - os.umount('/flash')' J$ }) Z8 A" z8 e4 l+ T
- p1 = pyb.Flash(start=0, len=256*1024)" b. }$ I4 \# y7 x# d! G) _1 z
- p2 = pyb.Flash(start=256*1024)
1 ~% l" o. ]7 a- a+ R8 K - os.VfsFat.mkfs(p1)
/ E l1 y8 R8 c2 |2 h0 z - os.VfsLfs2.mkfs(p2); f* }: l6 z* j5 N+ n" \5 G
- os.mount(p1, '/flash')1 {9 h9 s% }! ]) _/ c! b
- os.mount(p2, '/data')
1 Q" q) l# u7 {' ~$ ] k. P) x - os.chdir('/flash')
复制代码 2 W" y$ ]* M( U# P9 h
. ~" J1 T, ~9 T+ w" w
* a" c8 D8 @& j' g, K \, U这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb! V$ C; a! j6 V) t0 O- l
- p2 = pyb.Flash(start=256*1024)- ]6 u, m0 v) @8 @$ F j& W- F. y- P
- os.mount(p2, '/data')
复制代码 + D2 i' g- v/ M! t& m; j: g
* _2 {( g! d/ @% I# {
3 W( r9 G7 W4 [) d- t! L! j来 boot.py挂载数据分区。 # c% ^" t7 P: I) @0 L
混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os T7 P" e7 k8 x8 E- i4 S+ Z, @, S7 I+ I
- p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')' A' a+ ~- i) w9 k; }0 x( z( d! [
- os.mount(p, '/foo')
复制代码
1 S" F: Z# I" w0 m* t3 Q+ Q- l/ n% U& `1 }8 i
! R, ]+ f- C1 i: o
8 `# R/ J; r" g3 n" B* A8 M& A* d5 T& ^" l y# [
6 @6 e9 f' f" x- b- E" u8 @8 @( u" I/ @ |