micropython编程爱好网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 43022|回复: 0

使用文件系统

[复制链接]

24

主题

24

帖子

2340

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2340
发表于 2022-1-20 10:06:07 | 显示全部楼层 |阅读模式
使用文件系统

内容

) K0 O6 F4 h3 X" m5 R

本教程介绍 MicroPython 如何提供设备上的文件系统,允许将标准 Python 文件 I/O 方法与持久存储一起使用。

MicroPython 会自动创建默认配置并自动检测主文件系统,因此如果您想修改分区、文件系统类型或使用自定义块设备,本教程将非常有用。

文件系统通常由设备上的内部闪存支持,但也可以使用外部闪存、RAM 或自定义块设备。

在某些端口(例如 STM32)上,文件系统也可以通过 USB MSC 连接到主机 PC。pyboard.py 工具还为主机 PC 提供了一种访问所有端口上的文件系统的方法。

注意:这主要用于 STM32 和 ESP32 等裸机端口。在带有操作系统的端口(例如 Unix 端口)上,文件系统由主机操作系统提供。

虚拟FS

MicroPython 实现了一个类 Unix 虚拟文件系统 (VFS) 层。所有挂载的文件系统都组合成一个单一的虚拟文件系统,从 root 开始 /。文件系统被挂载到这个结构的目录中,并且在启动时工作目录被更改为主文件系统被挂载的位置。

在 STM32/Pyboard 上,内部闪存安装在 /flash,可选的 SDCard安装在/sd。在 ESP8266/ESP32 上,主文件系统挂载在 /。

1 z; E+ @5 V. k
块设备

块设备是实现 uos.AbstractBlockDev协议的类的实例 。

内置块设备

端口提供内置块设备来访问它们的主闪存。

开机时,MicroPython 将尝试检测默认闪存上的文件系统并自动配置和挂载它。如果没有找到文件系统,MicroPython 将尝试创建一个跨越整个闪存的 FAT 文件系统。端口还可以提供一种机制来“恢复出厂设置”主闪存,通常是通过在开机时按下按钮的某种组合。

STM32 / Pyboard

pyb.Flash类,可以访问内部闪存。在一些具有较大外部闪存的板上(例如 Pyboard D),它将使用它来代替。该 startkwarg应始终指定,即 pyb.Flash(start=0)。

注意:为了向后兼容,当构造没有参数时(即 pyb.Flash()),它只实现简单的块接口并反映呈现给 USB MSC 的虚拟设备(即它在开始时包含一个虚拟分区表)。

8 o* M5 \( U/ C2 X* q
ESP8266

内部闪存作为块设备对象公开,该对象 flashbdev 在启动时在模块中创建 。默认情况下,此对象作为全局变量添加,因此通常可以简单地作为bdev. 这实现了扩展接口。

- h; G( I) C4 ^6 w9 o/ s, @* `
ESP32

esp32.Partition类用于实现为板限定分区的块设备。与 ESP8266 一样,有一个全局变量 bdev指向默认分区。这实现了扩展接口。

+ ]" D4 {( o6 H% p6 h

) _( \& M8 u! i- `+ ~: W# I自定义块设备

以下类实现了一个简单的块设备,该设备使用以下命令将其数据存储在 RAM 中 bytearray:

  1. class RAMBlockDev:7 ]7 F, K4 m" W7 z+ l7 q. ?
  2.     def __init__(self, block_size, num_blocks):
    / F! t1 ]* A& A( k
  3.         self.block_size = block_size
    8 _; L8 P, C) l1 A5 [* M' l8 m* K/ T  \
  4.         self.data = bytearray(block_size * num_blocks)
    , o& J6 ?9 n% E, D% M1 c

  5. - f/ v  P7 h: k! ^4 |
  6.     def readblocks(self, block_num, buf):# E; v6 N% ~5 ^
  7.         for i in range(len(buf)):7 q- H  c) Z  Y4 O1 G, A$ s0 N0 D' D
  8.             buf[i] = self.data[block_num * self.block_size + i]
    7 W. R, w6 W4 h- ?3 }8 y
  9. % ^9 R% C3 @! P/ K- K
  10.     def writeblocks(self, block_num, buf):; p4 ?. @* v3 \) u5 F
  11.         for i in range(len(buf)):0 b  ]) g5 n) I5 _2 ^! r7 H
  12.             self.data[block_num * self.block_size + i] = buf[i]2 R' B( N+ b/ d! G- h& U  U

  13. - x0 f2 ^9 J3 c# c
  14.     def ioctl(self, op, arg):
    : o% B8 h% R4 B( E
  15.         if op == 4: # get number of blocks! E0 {- @, c! J5 E% G
  16.             return len(self.data) // self.block_size$ P  R5 D1 {! m7 X& w. \
  17.         if op == 5: # get block size
    : M& G9 M) A% w, o4 Z
  18.             return self.block_size
复制代码
7 y- F, Z* V/ p" {8 _
" Y+ @* {  c/ n5 J
- Q1 R! q) H# T6 d0 [4 f3 _( g: L

它可以按如下方式使用:

  1. import os
    ; R0 O* Y" w. c% V. Q8 {

  2. 4 J4 q& x* k. x! d7 e( W2 q
  3. bdev = RAMBlockDev(512, 50)# ^  S1 |- e2 j- W1 k4 R' c
  4. os.VfsFat.mkfs(bdev)
    / ?' H4 h. R2 S: M
  5. os.mount(bdev, '/ramdisk')
复制代码
) d  u7 D! z- e, k" c/ D% I
  J1 u5 ^, O) v4 T! G5 p0 h

! {' F# z1 W) I+ _8 F+ T6 U

支持简单接口和扩展接口(即 uos.AbstractBlockDev.readblocks()uos.AbstractBlockDev.writeblocks() 方法的签名和行为)的块设备的示例 是:

  1. class RAMBlockDev:
    # ^9 m$ A0 I" h' H! ]/ W
  2.     def __init__(self, block_size, num_blocks):
    / r; R9 V7 P- n# E
  3.         self.block_size = block_size  f# O4 I+ i; z- Q3 y
  4.         self.data = bytearray(block_size * num_blocks)5 q2 S8 f9 \3 X4 W4 S# q/ J
  5. 0 X* {, r* k4 f5 f& s5 {" F
  6.     def readblocks(self, block_num, buf, offset=0):
    : E9 {6 L' J9 |# u( w0 N
  7.         addr = block_num * self.block_size + offset
      M# J3 m  o- ^' n& B
  8.         for i in range(len(buf)):
    ) F1 N( I% W' V8 [
  9.             buf[i] = self.data[addr + i]
      w0 ^9 X& G3 ?3 p, L8 K

  10. % C8 d5 E  E3 V
  11.     def writeblocks(self, block_num, buf, offset=None):
    7 z+ z2 U1 H% v) F' J
  12.         if offset is None:
    - c" P+ @; ^5 k- N
  13.             # do erase, then write
    + g' g. H! e: h9 t3 |, k0 P
  14.             for i in range(len(buf) // self.block_size):6 i1 l9 q" ?+ C* z0 b$ J; h
  15.                 self.ioctl(6, block_num + i)1 ?; G# D9 p  Q% P/ i5 v
  16.             offset = 0, x6 o' L: F$ M. N+ o: @/ w
  17.         addr = block_num * self.block_size + offset- C: \- s$ M( a5 Y0 [
  18.         for i in range(len(buf)):' e. K6 |& |& d/ [: O1 e3 H' y
  19.             self.data[addr + i] = buf[i]
    / l) U7 m& S! \' f% T2 M7 @4 Z

  20. 7 c. M1 U: }5 `3 _& r9 \
  21.     def ioctl(self, op, arg):
    ( f4 N3 y4 G+ x2 R' w6 D* q
  22.         if op == 4: # block count
    + A+ u4 ~" l0 E
  23.             return len(self.data) // self.block_size
    % c# v/ ?* J& S8 X
  24.         if op == 5: # block size2 @) ~, p8 o& g& |& f
  25.             return self.block_size( ^4 H8 R* ]) v7 u5 p, ]3 a9 E
  26.         if op == 6: # block erase+ N( @5 T0 I3 \( @
  27.             return 0
复制代码
, |' G1 w- y4 W* h2 C6 `$ t5 `

, p- a6 v! T/ F7 r
+ s* H' V: [/ z& ], O# l3 F) V

由于它支持扩展接口,因此可以用于littlefs:

  1. import os4 |# H; ^. {# B0 m$ i, o7 ^- P
  2. ( F7 T; i; w4 ^/ T
  3. bdev = RAMBlockDev(512, 50)8 a8 o( w" y  ?; J: G' y2 K6 N: {
  4. os.VfsLfs2.mkfs(bdev)
    " t0 c7 S# ~; `& J0 J
  5. os.mount(bdev, '/ramdisk')
复制代码

0 f5 |- f+ z+ C$ N  h2 f
  b9 Y: A2 A3 y0 k3 t( v0 j4 }+ A) m1 m& N

一旦挂载,文件系统(无论其类型如何)就可以像通常在 Python 代码中使用的那样使用,例如:

  1. with open('/ramdisk/hello.txt', 'w') as f:
    9 S; e4 W, R) y
  2.     f.write('Hello world')8 v" j4 Y- K3 S$ `0 ]+ R4 Q
  3. print(open('/ramdisk/hello.txt').read())
复制代码

5 ~7 t! z( f5 M
' @' E8 X  i( |) l6 y% R/ a( o# t8 S9 Q  ?4 l1 e8 x$ O
! D: Q# k" B0 M# s  Y

; w. C% D; m# {2 c$ B# p5 I* d文件系统

MicroPython 端口可以提供 FAT、 和 的实现。 littlefs v1 and littlefs v2.

下表显示了固件中默认包含给定端口/板组合的文件系统,但可以在自定义固件构建中选择启用它们。


- I* z- c& e1 u) i1 h2 a% a* O* yFAT

FAT 文件系统的主要优点是它可以通过支持的板(例如 STM32)上的 USB MSC 访问,而主机 PC 上不需要任何额外的驱动程序。

但是,FAT 不能容忍写入期间的电源故障,这可能会导致文件系统损坏。对于不需要 USB MSC 的应用,建议使用 littlefs 代替。

要使用 FAT 格式化整个闪存:

  1. # ESP8266 and ESP32% N; P. i* E6 {5 y- O
  2. import os2 r" ~; G* \( _4 _% m' X
  3. os.umount('/'); Z% M$ g8 x* X' T3 a
  4. os.VfsFat.mkfs(bdev)
    2 A6 Z# G: v8 ^
  5. os.mount(bdev, '/')
    ; P6 z6 U+ g1 h. B) n* P: D7 E

  6. 7 x: ]( y6 C1 L; d2 ]# a# v5 `+ p
  7. # STM32; k0 r* H6 @8 j( l, q- a
  8. import os, pyb
    7 D5 L: ]. V' p" B$ V
  9. os.umount('/flash')5 E9 P) [: h) }( x+ J; x& b4 h
  10. os.VfsFat.mkfs(pyb.Flash(start=0))4 _- X2 n- V7 L3 T
  11. os.mount(pyb.Flash(start=0), '/flash')) t! |8 B- h8 Y5 `
  12. os.chdir('/flash')
复制代码

8 z# g5 M/ R7 j4 y) U' w5 q- \3 p3 T7 n' r; r0 ]+ O

1 G# Q( j; X7 e- g/ c" j7 h# T0 l
/ Z' s5 [  l+ {% o% {. X+ cLittlefs

Littlefs是专为基于闪存的设备设计的文件系统,对文件系统损坏具有更强的抵抗力。

笔记

有报告称 littlefs v1 和 v2 在某些情况下会失败,有关详细信息,请参阅littlefs issue 347littlefs issue 295.

& D) W& L/ H$ o% S- `7 W, w& l

注意:它仍然可以使用 littlefs FUSE 驱动程序通过 USB MSC 访问。请注意,您必须使用该-b=4096 选项来覆盖块大小。

使用 littlefs v2 格式化整个闪存:

  1. # ESP8266 and ESP32* T# z! D3 r% ~6 l) a
  2. import os
    % H4 {" T3 r( D& c: C
  3. os.umount('/')9 x7 D9 t0 B* y
  4. os.VfsLfs2.mkfs(bdev)
    $ B* t: L. u4 m  _
  5. os.mount(bdev, '/')4 d$ e! I$ W: ~, q
  6. 4 a# g5 B* w" ]5 A5 R9 O
  7. # STM32
    % S5 l" M1 D( J: M8 v) u! f
  8. import os, pyb3 b. T9 f1 z" `) q
  9. os.umount('/flash')
    7 H7 q# b( y& A' C3 q7 Y, y
  10. os.VfsLfs2.mkfs(pyb.Flash(start=0))
    : J3 P4 V1 m+ R' v5 G
  11. os.mount(pyb.Flash(start=0), '/flash')
    / g8 V+ c7 ?2 @2 R; l- f3 F1 H
  12. os.chdir('/flash')
复制代码
! X; h8 y/ J- h
. e( @1 _# t7 N4 n) C- q9 I& f4 j
  o, W$ B. X) p/ o
/ d" T# H. I2 s8 H2 f( K1 X# J; v
混合 (STM32)

通过使用 start 和 len kwargs to pyb.Flash,您可以创建跨越闪存设备子集的块设备。

例如,将第一个 256kiB 配置为 FAT(并通过 USB MSC 可用),其余配置为 littlefs:

  1. import os, pyb7 M% G% X- @9 O( ?% |, c* o
  2. os.umount('/flash')
    & Z5 o5 T/ D* P( i+ u
  3. p1 = pyb.Flash(start=0, len=256*1024)+ z. N$ G* U. f
  4. p2 = pyb.Flash(start=256*1024)
    - a1 `2 h4 M, _
  5. os.VfsFat.mkfs(p1)
      e" m; E: ~/ b5 F
  6. os.VfsLfs2.mkfs(p2)8 }7 Q# U+ B, z  x. \0 O9 h
  7. os.mount(p1, '/flash')
    6 s+ W' v/ t" P, E$ v3 v' [$ T0 ^
  8. os.mount(p2, '/data')
    8 ]& R( J) L+ V5 o5 N$ {2 H# Y! D
  9. os.chdir('/flash')
复制代码

: x* \- Z8 i6 B5 U8 W) l$ i. H
8 K+ y4 H; f1 f) Q
  J; i1 f6 h7 ?! u

这可能有助于使您的 Python 文件、配置和其他很少修改的内容通过 USB MSC 可用,但允许频繁更改的应用程序数据驻留在 littlefs 上,从而具有更好的电源故障恢复能力等。

偏移处的分区 0 将自动挂载(并自动检测文件系统类型),但您可以添加:

  1. import os, pyb7 v1 M- ]* k$ |7 ~
  2. p2 = pyb.Flash(start=256*1024)
    # k0 U1 O1 g' d+ _4 v! r' r
  3. os.mount(p2, '/data')
复制代码
8 ~% p4 x' c/ N* Y+ u6 z4 o2 i

. i+ `1 b: O1 U; x
# S) r% I; p, \

来 boot.py挂载数据分区。

9 C+ U( E8 k5 g, D$ U
混合动力(ESP32)

在 ESP32 上,如果您构建自定义固件,您可以修改 partitions.csv以定义任意分区布局。

启动时,名为“vfs”的分区将被/默认挂载,但任何额外的分区都可以boot.py 使用:

  1. import esp32, os& b6 J6 @7 e6 f& ^% @( q6 P
  2. p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')0 H" k! B5 B  b# n
  3. os.mount(p, '/foo')
复制代码

& }. e  E1 v6 X/ |
0 o% ~. U0 Y+ r' D# E" u  `/ l7 u8 K7 f. K7 Z# S8 [+ h
4 N6 W# y# |4 F- F# z6 F

9 |; M' j* b$ I( X4 w5 Z1 X, m, F$ ~5 k" j' \! |

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|micropython编程爱好网 ( 粤ICP备14010847号-3 ) microPython技术交流 microPython技术交流2

粤公网安备 44030702001224号

GMT+8, 2024-5-11 05:23 , Processed in 0.187201 second(s), 21 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表