micropython编程爱好网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4911|回复: 0

使用文件系统

[复制链接]

24

主题

24

帖子

1444

积分

管理员

Rank: 9Rank: 9Rank: 9

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

内容

* D7 C! o4 |, u0 ?

本教程介绍 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 上,主文件系统挂载在 /。


9 X. E0 k& `( R) A) v' g( t  b* R块设备

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

内置块设备

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

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

STM32 / Pyboard

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

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

/ x+ w- f9 g9 r$ U
ESP8266

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

3 r! N; G1 `* k$ _" _
ESP32

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

, ~' I2 K+ Y: ?1 z
, V! p0 z! w9 |2 y4 d; l- n& b6 h+ d: M/ J
自定义块设备

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

  1. class RAMBlockDev:
    6 ?! ]  }- \) }" W2 h, q
  2.     def __init__(self, block_size, num_blocks):
    ! H* s4 A9 g4 W3 o6 G, o. V# q3 B
  3.         self.block_size = block_size
    ' I, w2 u# n$ d9 H) i" f' U5 w' X; f
  4.         self.data = bytearray(block_size * num_blocks)
    / z: O7 f' w; _* s+ K

  5. ) y$ r5 n  l# C
  6.     def readblocks(self, block_num, buf):' M; m4 d/ v4 h6 R
  7.         for i in range(len(buf)):
    5 l7 e$ d+ U; |$ x; A3 N5 t1 C
  8.             buf[i] = self.data[block_num * self.block_size + i]
    3 v/ ?+ `; C, ^, O0 B3 K1 z$ l7 K

  9. 1 x0 e- h& v& _1 u
  10.     def writeblocks(self, block_num, buf):6 x1 I# \# f9 h: ]& |' c: J( [
  11.         for i in range(len(buf)):7 \0 L" a/ H5 E" j9 W4 J
  12.             self.data[block_num * self.block_size + i] = buf[i]
    $ b/ ^# C- d6 V  ]1 d4 L
  13. 1 o5 X7 \* j% y. w" _0 y+ S, j
  14.     def ioctl(self, op, arg):, ?$ I' f5 h7 `# M
  15.         if op == 4: # get number of blocks
      N! E5 ~8 j! L1 Q9 |2 v( ]
  16.             return len(self.data) // self.block_size0 h/ ~/ r" J6 K# n$ V2 m+ B% Y
  17.         if op == 5: # get block size
    ; p. C2 C9 d* g9 @+ H
  18.             return self.block_size
复制代码

' v1 E* V& b" p, A7 o
( I2 f" a# m, k- Q& }* Q! O, R1 ^5 ^, [7 v, ~7 Y

它可以按如下方式使用:

  1. import os3 s4 |0 |5 M4 S7 @. c/ \
  2. 5 v2 q) q+ n( P" {% R& h9 v, ?/ @
  3. bdev = RAMBlockDev(512, 50)) r2 o" v: o% U" W- X! O: t; f
  4. os.VfsFat.mkfs(bdev)
    ; `% {5 ~6 ]) i. n, e
  5. os.mount(bdev, '/ramdisk')
复制代码
0 |, J8 i% U/ |# E

$ L& }; J* s' X# v) a: B" M- E
6 u. o3 q5 V0 |( x

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

  1. class RAMBlockDev:
    9 z" r) X0 Q/ c# W. a: u6 O& n
  2.     def __init__(self, block_size, num_blocks):& C% U, r" Z, r: {* e- l
  3.         self.block_size = block_size2 q: O, U8 j& h/ H- Q' [
  4.         self.data = bytearray(block_size * num_blocks)4 Y! Q+ z3 z6 U% d  ^

  5. : L2 h' m* g8 I- {2 [
  6.     def readblocks(self, block_num, buf, offset=0):
    $ U( f: t) y. `/ R" t$ j
  7.         addr = block_num * self.block_size + offset
    & Y- ?% o7 c0 I6 E$ N
  8.         for i in range(len(buf)):, ~  T( D0 O7 `& n6 u1 s
  9.             buf[i] = self.data[addr + i]* K* ?5 L  K4 I* i4 [9 E
  10. 5 J2 s; ]0 Q2 T! ~
  11.     def writeblocks(self, block_num, buf, offset=None):
    1 B7 H3 k- @/ Y4 e
  12.         if offset is None:
    0 d: K1 t" [2 l6 y9 n
  13.             # do erase, then write' v( b% e1 m7 u9 K4 g. X& p) B
  14.             for i in range(len(buf) // self.block_size):
    , Y' Q8 f4 ]2 P* T! l
  15.                 self.ioctl(6, block_num + i)
    : E  [2 M% P4 {8 ]- p0 C% X
  16.             offset = 0
    2 e2 S, d, E" [: \: `! B' Q
  17.         addr = block_num * self.block_size + offset
    8 g, r5 H( O) o# v; z
  18.         for i in range(len(buf)):/ c$ p; F* ?; |0 h' b/ b( C9 Q, _! n
  19.             self.data[addr + i] = buf[i]* O: F1 v6 l5 w, E; Y9 F

  20. , {; J, N2 J, O( ?
  21.     def ioctl(self, op, arg):
    9 N2 D  {8 m3 d0 [8 z
  22.         if op == 4: # block count
    ) i+ \# w: L# R* D
  23.             return len(self.data) // self.block_size; Q' d, t  V' M; _, ^8 S
  24.         if op == 5: # block size
    5 d9 k% r* ~7 R; |
  25.             return self.block_size
    " \9 {5 U: H( s$ r# M
  26.         if op == 6: # block erase
    $ J8 y; X0 w$ X0 u
  27.             return 0
复制代码

7 V$ t6 O0 z9 X6 i
. K9 D1 p  ^; a8 P' [/ R
3 w" s4 @: K. z) _

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

  1. import os: y5 m  W  k* g" c4 \" J

  2.   j% e% D0 X* W" i
  3. bdev = RAMBlockDev(512, 50): g6 V, g0 E+ G6 P
  4. os.VfsLfs2.mkfs(bdev)
    ( |1 F) p( u* E/ b
  5. os.mount(bdev, '/ramdisk')
复制代码
7 d; V9 w2 ~1 [3 R

0 P9 V  r6 W. D1 V* R1 I  n( r" S9 }& }  e

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

  1. with open('/ramdisk/hello.txt', 'w') as f:
    1 {: n3 ^) Y6 g9 ~: m' B
  2.     f.write('Hello world')+ z: ^4 y7 g1 q5 o1 n2 y
  3. print(open('/ramdisk/hello.txt').read())
复制代码
% B' }( I5 w' g" E& C+ N

3 P6 r- {( J$ V$ l$ Z6 o5 q) j
% @0 v" S3 e2 _) c: R* t% b1 b) T$ c+ N) e0 B7 G6 B% m% `& L/ b

7 i/ y4 G6 ~( p文件系统

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

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

; M( v9 x  p" E' X
FAT

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

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

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

  1. # ESP8266 and ESP32, v) T2 Z5 o) B# @9 N) U7 Y4 ~
  2. import os0 j/ z5 N& f4 p2 Q0 w+ t
  3. os.umount('/')
    ( ?/ k; `& w+ x4 i) m
  4. os.VfsFat.mkfs(bdev)
    2 P# {  a) n' n
  5. os.mount(bdev, '/')
    ' }$ O. W* ]6 @1 H0 ^( ?  m/ m* O# R

  6. + H5 S2 x! N7 x; ^
  7. # STM32$ k  z/ Q% N2 C" Z: E
  8. import os, pyb% Z9 G5 Q* W0 f; j
  9. os.umount('/flash')
    : b) u5 y% h1 }! l/ _3 l
  10. os.VfsFat.mkfs(pyb.Flash(start=0))
    ) k9 o& _& U( c
  11. os.mount(pyb.Flash(start=0), '/flash')
    . S1 D% }8 [0 b1 R8 `! h
  12. os.chdir('/flash')
复制代码

" {* C! @' r$ j1 \# e" r. M$ R) `( M/ C+ Z9 l; ^& t
# ?9 O+ C% R* g
; |: q8 L3 o* l2 u. k' N
Littlefs

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

笔记

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

8 m: U1 t$ B3 J) A

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

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

  1. # ESP8266 and ESP32
    * B; A) O( O( j) \. [, ]
  2. import os; g: L/ B  r# a8 n
  3. os.umount('/')* Y# I$ e9 h! B9 Q) Z- ~; q" T
  4. os.VfsLfs2.mkfs(bdev)& }: h- @. j# x  r1 g
  5. os.mount(bdev, '/')
    " g" e) A4 u2 c. Q1 U4 I

  6. 8 w/ p" A' q- ~; n- a- M
  7. # STM320 h3 [  S- ~; ]3 Y9 G$ a
  8. import os, pyb5 d* l2 H& l+ S  [; m4 n
  9. os.umount('/flash')
    / s1 y9 ]( s, ~5 ~  _
  10. os.VfsLfs2.mkfs(pyb.Flash(start=0))4 W1 S3 v0 [* ]0 q
  11. os.mount(pyb.Flash(start=0), '/flash')
    ) x# J* w8 l: F( [7 i/ `
  12. os.chdir('/flash')
复制代码

& a7 M! _- k7 D8 h
% u3 ]. d' h# o1 f3 z( V- i; T4 C7 w" y" d

. a1 A% I0 }! ~: M8 _1 S( t7 ?- i混合 (STM32)

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

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

  1. import os, pyb
    9 P  ^8 ]4 ?' p. \) P, \# y
  2. os.umount('/flash')& L8 H) @; V7 K7 n9 V
  3. p1 = pyb.Flash(start=0, len=256*1024)- Q* A' Q) r9 r5 d, U5 u
  4. p2 = pyb.Flash(start=256*1024)
    , \5 [& _) Q8 M( ~+ `4 o7 L& P
  5. os.VfsFat.mkfs(p1)
    0 S0 Q; m( l# s+ H/ S/ {' N8 o. r3 o
  6. os.VfsLfs2.mkfs(p2)
    0 `% i3 J$ L2 _
  7. os.mount(p1, '/flash')
    6 h' ?+ i( Y( H+ \1 i- K
  8. os.mount(p2, '/data')& F1 w! Z7 Q0 T6 M  e
  9. os.chdir('/flash')
复制代码

, ~# c7 x7 Q) q7 {2 v
$ t% p4 l0 I! B$ r+ ]: ]6 j" z
& |0 r' s! [% T( T! |# ^7 N

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

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

  1. import os, pyb
    ; z4 E2 d+ k  d- [" B# P, l
  2. p2 = pyb.Flash(start=256*1024)% A* @- i' `$ j. T
  3. os.mount(p2, '/data')
复制代码

' ^/ j) s8 c" ?8 N: h' m% {
3 v' a8 |7 k  a& @! c  k' p, o5 o- L9 H: @  n0 ]% A

来 boot.py挂载数据分区。

/ B- y7 `0 ^  ~+ J
混合动力(ESP32)

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

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

  1. import esp32, os) ^. E" t7 t7 x/ y8 k6 h
  2. p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')& X1 b; X. W7 Y* ]* i9 V
  3. os.mount(p, '/foo')
复制代码
& o: j% X) @7 k0 m9 ^
: ?; C: J  I6 T/ O
! e: u& y/ Z' H$ X

! z8 t& y& m! O& D
7 n( z* Y+ ]7 R$ R) Q1 s

) _3 m; c/ N: l4 x, ?* F! W

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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

粤公网安备 44030702001224号

GMT+8, 2022-7-5 12:28 , Processed in 0.218401 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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