該文件介紹了MicroPython如何在裝置上構建檔案系統,以允許使用者使用標準Python檔案輸入/輸出方法來進行持久化儲存。其啟動後會自動檢測所適合的主檔案系統並建立預設配置,因此,該篇文件的作用主要體現在你需要修改預設分割槽和檔案系統型別或使用自定義塊裝置的時候。
檔案系統通常構建在裝置上的片內Flash儲存器上,但也可以構建在外部Flash,RAM或者自定義塊裝置上。在某些移植版本上(比如STM32),檔案系統能夠以USB大容量儲存裝置形式同時供主機電腦使用。pyboard.py工具還為主機電腦提供了一種訪問所有MicroPython移植版本上檔案系統的方法。
注意:此處所述檔案系統主要用於STM32和ESP32等裸機移植版本,而在其本身已帶有作業系統的移植版本上(比如Unix移植版本),檔案系統由主機系統來提供。
VFS
MicroPython實現了類Unix的虛擬檔案系統(VFS)層。所有掛載的檔案系統均被合併到一個以"/"為根節點而開始的虛擬檔案系統中,檔案系統以目錄結構的形式進行掛載,並且在裝置啟動時,當前工作目錄被自動切換到主檔案系統所在之處。
在STM32/Pyboard上,片內Flash會被掛載到/flash目錄,若已插入SD卡,其可以被掛載到的/sd目錄。在ESP8266/ESP32上,主檔案系統則會被掛載到"/"目錄。
塊裝置
每個塊裝置均對應為實現了uos.AbstractBlockDev介面協議的類例項,該介面協議包含簡單介面和擴充套件介面,簡單介面可為FAT檔案系統所用,擴充套件介面可為littlefs檔案系統所用。
1> 內建塊裝置
MicroPython各移植版本均提供了內建塊裝置以存取其主Flash。
裝置上電時,MicroPython會自動檢測預設Flash上所用檔案系統並進行適當配置和掛載。如果未檢測到檔案系統,其進而會嘗試在整個Flash上建立FAT檔案系統。MicroPython各移植版本一般還提供對主Flash進行“恢復出廠設定”的方法,通常由在上電時按適當的組合按鍵來進行。
2> STM32/Pyboard
pyb.Flash類提供了對片內Flash的存取方法。在一些具有更大容量外部Flash的開發板上(比如Pyboard D),其會轉而使用外部Flash。該類的start引數應總是傳遞實際有效值,不推薦為空,比如pyb.Flash(start = 0)。
注意,為了向後相容,當該類進行無參構造時(比如pyb.Flash()),其僅實現了簡單塊裝置介面,並將以USB大容量儲存形式的虛擬裝置進行展現(即在開始包含一個虛擬分割槽表)。
3> ESP8266
其板載Flash以塊裝置物件的形式進行展現,該物件由flashbdev模組在系統開機的時候進行建立。該裝置物件預設被新增為全域性變數,通常可以簡單地透過bdev來進行訪問,其實現了uos.AbstractBlockDev的擴充套件介面。
4> ESP32
esp32.Partition類利用開發板上的儲存分割槽實現了塊裝置介面。和ESP3266一樣,全域性變數bdev指向了其預設分割槽,其也實現了uos.AbstractBlockDev的擴充套件介面。
自定義塊裝置
如下示例實現了簡單塊裝置介面,其使用bytearray在RAM中儲存資料。
class RAMBlockDev: def __init__(self, block_size, num_blocks): self.block_size = block_size self.data = bytearray(block_size * num_blocks) def readblocks(self, block_num, buf): for i in range(len(buf)): buf[i] = self.data[block_num * self.block_size + i] def writeblocks(self, block_num, buf): for i in range(len(buf)): self.data[block_num * self.block_size + i] = buf[i] def ioctl(self, op, arg): if op == 4: # get number of blocks return len(self.data) // self.block_size if op == 5: # get block size return self.block_size
其能夠以如下方式被使用:
import osbdev = RAMBlockDev(512, 50)os.VfsFat.mkfs(bdev)os.mount(bdev, '/ramdisk')
如下示例同時實現了簡單塊裝置介面和擴充套件塊裝置介面(能夠同時支援帶偏移量引數的uos.AbstractBlockDev.readblocks() 和uos.AbstractBlockDev.writeblocks()函式呼叫):
class RAMBlockDev: def __init__(self, block_size, num_blocks): self.block_size = block_size self.data = bytearray(block_size * num_blocks) def readblocks(self, block_num, buf, offset=0): addr = block_num * self.block_size + offset for i in range(len(buf)): buf[i] = self.data[addr + i] def writeblocks(self, block_num, buf, offset=None): if offset is None: # 先擦除後寫入 for i in range(len(buf) // self.block_size): self.ioctl(6, block_num + i) offset = 0 addr = block_num * self.block_size + offset for i in range(len(buf)): self.data[addr + i] = buf[i] def ioctl(self, op, arg): if op == 4: # 取得塊數量 return len(self.data) // self.block_size if op == 5: # 取得塊大小 return self.block_size if op == 6: # 塊擦除 return 0
由於其支援擴充套件介面,便能夠以littlefs檔案系統形式被使用:
import osbdev = RAMBlockDev(512, 50)os.VfsLfs2.mkfs(bdev)os.mount(bdev, '/ramdisk')
一旦被掛載後,無論其型別為何,檔案系統便都能夠以常規形式在Python程式碼中使用,例如:
with open('/ramdisk/hello.txt', 'w') as f: f.write('Hello world')print(open('/ramdisk/hello.txt').read())
檔案系統
MicroPython可以支援FAT,littlefs v1和littlefs v2檔案系統。如下表格展示了對於給定移植版本和開發板的組合,預設的系統韌體中所包含的檔案系統。當然,在你自己構建系統韌體時,可以依需要自己選擇並將其包含進去。
1> FAT檔案系統
FAT檔案系統的主要優勢是其所支援的開發板能夠作為USB大容量儲存裝置被主機訪問,而無需額外的驅動。然而,該檔案系統不能夠對在寫入時掉電的情況進行容錯處理,從而可能導致檔案系統損壞。對於不需要USB大容量儲存裝置的應用來講,推薦使用littlefs檔案系統。
採用FAT檔案系統格式化flash裝置的方法如下:
# ESP8266 and ESP32import osos.umount('/')os.VfsFat.mkfs(bdev)os.mount(bdev, '/')# STM32import os, pybos.umount('/flash')os.VfsFat.mkfs(pyb.Flash(start=0))os.mount(pyb.Flash(start=0), '/flash')os.chdir('/flash')
2> Littlefs檔案系統
Littlefs檔案系統被設計於專門使用在以flash為儲存的裝置上,其對檔案系統損壞的抵抗力更強。
注意:透過安裝littlefs FUSE驅動,其也能夠被作為USB大容量儲存裝置而存取。此時,必須使用
-b=4096選項來覆蓋其原本塊大小。
使用littlefs v2來格式化Flash的方法如下:
# ESP8266 and ESP32import osos.umount('/')os.VfsLfs2.mkfs(bdev)os.mount(bdev, '/')# STM32import os, pybos.umount('/flash')os.VfsLfs2.mkfs(pyb.Flash(start=0))os.mount(pyb.Flash(start=0), '/flash')os.chdir('/flash')
3> STM32混合檔案系統
透過使用pyb.Flash的start和len關鍵字引數,可以建立橫跨多個flash裝置及檔案系統的塊裝置。比如,如下程式碼可以將其前256KB配置為FAT檔案系統(能夠以USB大容量儲存裝置的形式被訪問),剩餘部分配置為littlefs:
import os, pybos.umount('/flash')p1 = pyb.Flash(start=0, len=256*1024)p2 = pyb.Flash(start=256*1024)os.VfsFat.mkfs(p1)os.VfsLfs2.mkfs(p2)os.mount(p1, '/flash')os.mount(p2, '/data')os.chdir('/flash')
採用這種方式可以使Python程式檔案、配置及其它很少修改的資料能夠以USB大容量儲存裝置的形式被訪問,而由於littlefs具有較好的電源故障恢復能力,可以將需要被頻繁修改的資料儲存其中。
MicroPython中只有偏移量為0的分割槽會被自動掛載(其檔案系統也會被自動檢測識別),但你可以新增如下程式碼到boot.py中以掛載其它資料分割槽:
import os, pybp2 = pyb.Flash(start=256*1024)os.mount(p2, '/data')
4> ESP32混合檔案系統
在ESP32上,當你構建自定義韌體時,可以透過修改partitions.csv檔案來定義任意的分割槽結構。系統啟動時,被命名為"vfs"的分割槽會被預設掛載到"/"目錄上,額外的分割槽可以在boot.py中使用如下程式碼掛載:
import esp32, osp = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')os.mount(p, '/foo')