使用文件系统 内容 使用文件系统
/ z# _: M6 x! N6 M虚拟FS 块设备 ! b9 S* B* R: d5 G
内置块设备 ' v N" L1 J r! O i
自定义块设备
* p, I9 a, j3 n9 H0 x: N
文件系统 " H& n+ M6 ~2 Y! M* \6 D
" j$ F% r. q) } M* G( T . w/ L2 p: x: V
# f/ }3 m9 b* c/ u- N0 o3 v
本教程介绍 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 上,主文件系统挂载在 /。
8 @0 h: Z( p+ v. ^ `4 w, h块设备块设备是实现 uos.AbstractBlockDev协议的类的实例 。 内置块设备端口提供内置块设备来访问它们的主闪存。 开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。 STM32 / Pyboard该pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。 注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。 3 |2 m/ Y$ ]# v7 ]/ ?4 ]0 x+ Y1 {% P
ESP8266内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。 % ?! ^' R0 s# N5 K7 U J
ESP32esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。 2 H. _6 T, C: P9 ^7 [: ]
% N) ?+ l4 {: d' y
自定义块设备以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray: - class RAMBlockDev:' I0 T6 p& P- t l5 X: }, G- P
- def __init__(self, block_size, num_blocks):, K: s& K+ l3 R6 I
- self.block_size = block_size
3 U2 [6 y- K# W r - self.data = bytearray(block_size * num_blocks)# p1 o7 G( q- m0 a0 G
% a: A! `) I7 R+ G, \6 m- def readblocks(self, block_num, buf):
# g4 I# r9 ~4 | - for i in range(len(buf)):& `. p' @" C5 [9 q0 |% Y9 l
- buf[i] = self.data[block_num * self.block_size + i]) p3 Q( u0 Y# ^7 O1 G7 }
- + ?3 {5 l3 F+ u: s) q8 m3 h, V( \
- def writeblocks(self, block_num, buf):7 _% z5 T) U; Z7 ^0 ^+ C
- for i in range(len(buf)):0 f& L; z* R, E. t: \& W
- self.data[block_num * self.block_size + i] = buf[i]( z# L: x) Y- j1 }& }2 E4 H+ E7 X
% C/ o. u% f5 ?2 w$ _8 @4 Y- def ioctl(self, op, arg):& u! I+ _/ s |
- if op == 4: # get number of blocks
0 g0 K; K, Q g" O8 V - return len(self.data) // self.block_size
- u2 Y- |6 M2 u) f - if op == 5: # get block size
) m! O! y: A1 u6 |- p& d$ T7 ` - return self.block_size
复制代码 $ O& O$ q# L) ~% a O1 S
z# o* S0 V. S* q5 w
* s# O5 z7 h0 m: w8 R( j它可以按如下方式使用: - import os s7 \$ }8 U. Q1 j5 V
- 9 |2 f( k& b9 [3 H+ |
- bdev = RAMBlockDev(512, 50)! i/ F0 r! Q' U0 o
- os.VfsFat.mkfs(bdev); K1 S$ ~! S k& k
- os.mount(bdev, '/ramdisk')
复制代码 ) R2 L8 I& G! ?
$ @; ?. q% X( d/ S$ `
L+ z+ w6 p- ]5 v- P
支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks() 和 uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是: - class RAMBlockDev:5 x/ C0 P/ j5 A4 f
- def __init__(self, block_size, num_blocks):% Z; r9 Q: i2 `+ l
- self.block_size = block_size0 _. W7 @- f. ^2 r; L/ _ \
- self.data = bytearray(block_size * num_blocks)
, |' j( k9 U/ @( j: J; q( b - - g+ x; g, I3 G- Q
- def readblocks(self, block_num, buf, offset=0):( a! {2 O4 W6 F1 J4 p4 ` r/ h% s
- addr = block_num * self.block_size + offset
( g9 W+ ^9 X5 ?2 l* U - for i in range(len(buf)):
/ b* Q U; d3 N1 F, Y - buf[i] = self.data[addr + i]9 \& p" i* J: J. \9 l$ u
- $ P# |$ |" i- E4 [0 t9 Y) e6 X. H
- def writeblocks(self, block_num, buf, offset=None):
2 V, M$ x1 o7 K# ~3 J - if offset is None:: u% p! P7 |6 @- ]! R/ [
- # do erase, then write
: I5 D2 d3 J/ E) Y5 l& d+ S - for i in range(len(buf) // self.block_size):7 D; |1 ?* r& v
- self.ioctl(6, block_num + i)" Y( B: N6 {2 c" l5 `" n
- offset = 0
2 b# t* a; d6 G' l7 _0 K0 Q - addr = block_num * self.block_size + offset5 i7 ^, i) M( q. I
- for i in range(len(buf)):
" e' T% i* u I/ O" o1 T. ~ - self.data[addr + i] = buf[i]2 W* H2 U5 G7 M5 R7 Q1 ^, H* q
- . F3 `4 t0 a# u: N. w
- def ioctl(self, op, arg):
7 d3 x8 r+ P8 j4 ^* @ - if op == 4: # block count* l" J3 u7 A. W1 j- Z' A0 k1 Q
- return len(self.data) // self.block_size7 h m+ @! h% ~6 p# ?7 y( s
- if op == 5: # block size: S3 p9 I( [7 G6 J
- return self.block_size
. P/ I3 J* X9 q& w% c% c - if op == 6: # block erase7 L; m$ k9 j) A+ w: ^. B
- return 0
复制代码
5 R$ r v; I! P5 F* T/ @3 E5 t2 k, g1 r! ~5 n
1 }6 l' w. @1 a( g. o由于它支持扩展接口,因此可以用于littlefs: - import os7 y7 u4 z. g1 C: z: ]- H ?
1 @- N9 q8 c: _( r- bdev = RAMBlockDev(512, 50)+ u5 b9 w3 Z( H0 C
- os.VfsLfs2.mkfs(bdev)% D, u0 {1 |! m# ], U
- os.mount(bdev, '/ramdisk')
复制代码 ! G; M. e, g" O+ p c: m3 q; [/ U
5 E5 n% V$ T& z3 C/ {: _. i/ O5 }
7 A& x( m6 m/ l5 ~
一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如: - with open('/ramdisk/hello.txt', 'w') as f:6 W+ f7 g. r2 U7 r; V, Q, K( l
- f.write('Hello world')
4 N S( Z, ^: S7 m - print(open('/ramdisk/hello.txt').read())
复制代码 7 }* \/ \3 x7 ^+ Z+ J
' G( r( Q( r: S' h6 |, r+ j8 E
) `5 T3 H' x6 y: \" J: k
: M h) m0 [" W) `( h
# U: O, D! l- i7 b R8 B* t文件系统MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2. 下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。 ' X) K; v$ k$ C: J; g9 W. k) d' c$ R
FATFAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。 但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。 要使用 FAT 格式化整个闪存: - # ESP8266 and ESP32
9 x+ ?( S8 e3 Q6 U" y/ h1 B2 [ - import os3 Q8 q+ k: X1 h/ f3 [4 b
- os.umount('/')
6 o5 v; M0 ?& ~% \; H& ]6 b - os.VfsFat.mkfs(bdev)# G4 l- l. w# L* j3 b. }
- os.mount(bdev, '/')
9 l" H- `9 |( ^7 q - & V; c0 C+ ^ c" S
- # STM32* \( f3 S: t& Y3 f
- import os, pyb
. B0 u2 t& ?) _' d& r# ` - os.umount('/flash')
0 q# y Q: S' P9 |/ ^# q - os.VfsFat.mkfs(pyb.Flash(start=0))
/ Y+ ?1 O, A$ D% S - os.mount(pyb.Flash(start=0), '/flash')
/ [% U" U* U1 C/ ]' K% l - os.chdir('/flash')
复制代码 - ]: x2 n. w# d+ W& H% p% T
% Y/ G2 ~& f8 n- f! B; F" F& o' b
" h* c: j5 p; }, K q
: M7 m, g1 E4 c) n L3 LLittlefsLittlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。 笔记 有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347 和 littlefs issue 295. , Y9 V0 l0 x# ?# K" A S% ]' L+ s/ Q$ f
注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。 使用 littlefs v2 格式化整个闪存: - # ESP8266 and ESP32
" ~# \2 k) q' g h5 g3 F. v - import os
- Q0 u, z1 C- E, Y' z7 p, e6 ] - os.umount('/') I! @, k; v, y" E% D1 C7 b/ `
- os.VfsLfs2.mkfs(bdev)2 Y) r2 Y; Q' O$ p% c" k7 I$ |
- os.mount(bdev, '/')4 n) V ?- c3 b9 q" i* Q
- 5 S- l! r7 E k+ l! U
- # STM32' C- f4 b6 D& {4 R# H8 F( O0 N) L
- import os, pyb9 P4 v# O% w4 V3 r# `3 n4 Q
- os.umount('/flash')$ e" e$ q0 `! B# E( E: Q
- os.VfsLfs2.mkfs(pyb.Flash(start=0))- ?% {' p. H W& s6 S) {$ v( ^; s
- os.mount(pyb.Flash(start=0), '/flash')
) R( `2 f. h% G* B' N- a9 D - os.chdir('/flash')
复制代码 / I/ s/ n( x* E/ h p
3 D, b5 S( A0 F( K" \
$ ]' K) |1 k+ ?. a$ ]0 { E$ a4 h( i7 ?+ {0 G% ~
混合 (STM32)通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。 例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs: - import os, pyb
4 R! ]; `. B- f - os.umount('/flash')8 j2 _8 {3 k4 [9 T
- p1 = pyb.Flash(start=0, len=256*1024)
( t) g9 ~4 ` I+ o+ M! x7 h - p2 = pyb.Flash(start=256*1024)
/ d. l: X: B' I2 j$ h1 E2 a1 Y% C - os.VfsFat.mkfs(p1)+ b) m4 m4 l' j" P0 m4 N2 P
- os.VfsLfs2.mkfs(p2)
, t0 P( [+ m8 Y2 d) n - os.mount(p1, '/flash')1 _$ q0 p$ i$ z: o1 t
- os.mount(p2, '/data')
/ p* b! c2 \ J( U0 u - os.chdir('/flash')
复制代码
- S4 |9 w9 ~: _% ]! n- o3 q; O, a1 h9 T: O7 J) x
`2 k# k9 s6 g$ j: r; S5 y" U这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。 偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加: - import os, pyb
+ e+ H6 X1 O; y. r7 P - p2 = pyb.Flash(start=256*1024)2 ^7 |# f9 O) F7 D9 q6 Z
- os.mount(p2, '/data')
复制代码
, ~: V8 x- e- h2 n0 _" O1 \; V' b. k; R5 |* i; s' Y
- p4 b( I3 y8 @/ s来 boot.py挂载数据分区。 / V; r( J+ w' f, o4 m9 B% a0 o/ [0 X
混合动力(ESP32)在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。 启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用: - import esp32, os, C' ]5 N/ E' W2 ~: \
- p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')
, g9 ~+ [% i# n7 P3 X1 g - os.mount(p, '/foo')
复制代码 4 l- C& h0 _' @' @5 e3 _3 s
7 m& Q/ c% |# J1 b5 q
* W) ]# d, y) N& w5 l
3 L; f" b F3 B$ B: g' M, h; s. r. \7 [3 `
1 x. B/ h" g4 w! J( c
|