LittleFS ist ein Dateisystem für den Flash-Speicher verschiedener Mikrocontroller. Auf den ESP-Controllern soll es die Nachfolge des weit verbreiteten SPIFFS antreten. Es bietet einige Vorteile wie echte Verzeichnisse, höhere Geschwindigkeit und bessere Stabilität, insbes. wenn das Dateisystem relativ voll ist. Ein Nachteil von LittleFS ist der höhere Platzbedarf kleiner Dateien – die minimale Sektorgröße ist 4 KB statt 256 Bytes bei SPIFFS. LittleFS speichert aber mehrere kleine Dateien in einem einzigen Sektor, um den Platzverbrauch zu reduzieren.
Der zweite Teil enthält eine ausführliche Anleitung zur Installation der Dateisystem-Tools, mit denen man in der Arduino-IDE ein Dateisystem so vorbereiten kann, dass es vorinstallierte Dateien enthält. Das Image (Abbild) des vorbelegten Dateisystems wird dann in den Flash-Speicher des ESP32 hochgeladen. Die Installation ist optional – man kommt auch ohne die Tools aus, wenn man kein Dateisystem mit vorinstallierten Dateien benötigt.
LittleFS als Nachfolger von SPIFFS
Auf dem ESP8266 ist LittleFS bereits Bestandteil des Cores, also der Systembibliotheken. Beim ESP32 ist das in Arbeit: In der espressif-Entwicklungsumgebung ESP-IDF ist LittleFS seit einiger Zeit enthalten. Im aktuellen ESP32-Paket für die Arduino-IDE (Version 1.0.6) ist es zwar noch nicht integriert, aber in den Entwicklerzweig (Version 2.0.0) wurde es schon aufgenommen und wird dann in neuen Versionen standardmäßig mitinstalliert.[1]Das Arduino-Paket für den ESP32 befindet sich bei Github: github.com/espressif/arduino-esp32; wer die Entwicklerversion ausprobieren möchte, muss in der Boardverwaltung der Arduino-IDE folgende URL … Continue reading
In der ESP8266-Dokumentation ist dem Kapitel zu SPIFFS ein Hinweis vorangestellt, der empfiehlt, SPIFFS nicht weiter zu verwenden und auf LittleFS umzusteigen, weil SPIFFS schon seit einiger Zeit nicht mehr weiterentwickelt wird (die letzte stabile Version 0.3.7 ist von Juli 2017).
SPIFFS Deprecation Warning
SPIFFS is currently deprecated and may be removed in future releases of the core. Please consider moving your code to LittleFS. SPIFFS is not actively supported anymore by the upstream developer, while LittleFS is under active development, supports real directories, and is many times faster for most operations.[2]Eigene Übersetzung: »SPIFFS wird derzeit als veraltet betrachtet und wird möglicherweise in zukünftigen Versionen des Kerns entfernt. Bitte denken Sie darüber nach, Ihren Code auf LittleFS … Continue reading
Die APIs beider Dateisysteme unterscheiden sich nicht, d.h. die Funktionsaufrufe, die man als Programmierer nutzt, sollen die gleichen sein – man muss nur bei allen Funktionsaufrufen die Angabe „SPIFFS” in „LITTLEFS” ändern. Da es noch keine offizielle LittleFS-Dokumentation gibt, verweisen die Entwickler auf die SPIFFS-Dokumentation:
See the official ESP-IDF SPIFFS documentation, basically all the functionality is the same; just replace spiffs with littlefs in all function calls.
Also see the comments in include/esp_littlefs.h [3]Komplettes Zitat von github.com/joltwallet/esp_littlefs (die Entwickler der LittleFS-Bibliothek für die ESP-IDF, die Grundlage der aktuellen ESP32-Bibliothek für die Arduino-IDE ist): »See … Continue reading
Ohne größere Änderungen am eigenen Code soll die Umstellung von SPIFFS auf LittleFS auch mit folgenden Anweisungen an den (Pre-)Compiler gehen (Quelle):
#define USE_LittleFS #include <FS.h> #ifdef USE_LittleFS #define SPIFFS LITTLEFS #include <LITTLEFS.h> #else #include <SPIFFS.h> #endif
Ob das in der Praxis tatsächlich so einfach ist, muss sich zeigen. Gerade das Vorhandensein von „echten” Verzeichnissen könnte in dem einen oder anderen Projekt Änderungen an der Programmlogik erforderlich machen.
Wenn man – wie ich – relativ neu mit eigenen Projekten startet, ist es vermutlich sinnvoll, gleich mit LittleFS statt SPIFFS einzusteigen. Da aber viel Beispielcode im Web auf SPIFFS beruht, muss man gucken, was sich auf LittleFS umstellen lässt und wo man vielleicht doch besser bei SPIFFS bleibt, wenn man ein fertiges Projekt nutzen will oder auf eine Bibliothek nicht verzichten kann, die SPIFFS als Dateisystem voraussetzt. Wegen der Ähnlichkeit der APIs dürfte es aber kein Problem sein, den Code des jeweils anderen Systems zumindest nachvollziehen zu können.
Performance und Overhead der verschiedenen Dateisysteme
Es gibt anders als bei SPIFFS bei LittleFS (theoretisch) keine Begrenzung der Anzahl gleichzeitig geöffneter Dateien.[4]Siehe github.com/joltwallet/esp_littlefs#documentation: »max_files field doesn’t exist since we removed the file limit«. In der Header-Datei LITTLEFS.h wird zwar beim Aufruf der … Continue reading
Außerdem verwendet LittleFS eine Dateistruktur mit echten Verzeichnissen. SPIFFS dagegen ist ein flaches Dateisystem – die Dateinamen sehen zwar so aus, als ob sie Directories enthielten, z.B. /dir1/dir2/datei.txt
, tatsächlich sind die Schrägstriche aber Bestandteile des Dateinamens.
In einer Diskussion zur LittleFS-Bibliothek findet man interessante Vergleiche der verschiedenen Dateisysteme bzgl. der Anzahl Dateien im Dateisystem und Overhead bei verschiedenen Dateigrößen. U.a. erfährt man dort, dass LittleFS mehrere kleine Dateien (bis 512 Bytes) in einem einzigen Block speichern kann; erst ab 513 Bytes belegt jede Datei einen eigenen Block. So ist es möglich, in LittlerFS deutlich mehr (kleine) Dateien zu speichern, als das Dateisystem Blöcke hat.
Wie LittleFS genau arbeitet, wird in der Beschreibung des Designs erläutert, zur Speicherung kleiner Dateien speziell im Bereich Files (kleine Dateien werden direkt zusammen mit den Verwaltungsinformationen gespeichert und belegen keine eigenen Datenblöcke).
Eine Diskussion im Arduino-Forum beschreibt SPIFFS als „Speicher-Katastrophe”, gerade wenn das Dateisystem zu mehr als der Hälfte gefüllt ist. Dort gibt es auch Grafiken, wie bei SPIFFS die Zugriffszeiten bei steigendem Füllgrad des Dateisystems deutlich ansteigen und wie sich FatFS und LittleFS im Vergleich dazu verhalten.
Einige Performance-Vergleiche der Dateisysteme gibt es auf der Seite der LittleFS-Bibliothek für die ESP-IDF.
Installation der LittleFS-Bibliothek
Da LittleFS noch kein Standarddateisystem für den ESP32 ist, muss man für die aktuelle Version des Arduino-ESP32-Pakets (Version 1.0.6; ebenso die Vorversionen) die LittleFS-Bibliothek und bei Bedarf ein paar Tools selbst installieren.[5]Welche Version man installiert hat, kann man in der Boardverwaltung überprüfen: Menü Werkzeuge → Board "xyz" → Boardverwalter…, dort im Suchfeld „esp” eingeben.Für … Continue reading In zukünftigen Versionen (ab 2.0) soll die LittleFS-Unterstützung in den ESP32-Core für Arduino integriert sein und man erspart sich die manuelle Installation.
Die LittleFS-Bibliothek installiert man am einfachsten mit der Arduino-Bibliotheksverwaltung (Menü Werkzeuge → Bibliotheken verwalten…
); als Suchbegriff kann man „littlefs” angeben und findet dann relativ weit unten in der Ergebnisliste den Eintrag „LittleFS_esp32”.
Will man sie manuell installieren, findet man sie auf Github unter der Adresse github.com/lorol/LITTLEFS.
(Ausführliche Hinweise zur Installation von Bibliotheken gibt der Beitrag Arduino-IDE: Bibliotheken verwalten.)
Standard-Dateisystem ist für den ESP32 SPIFFS; auch FatFS wird schon länger unterstützt, wie man an den verschiedenen Möglichkeiten zur Partitionierung des Flash im Menü Werkzeuge → Partition Scheme "xyz"
sieht, wenn als Board ein ESP32-Modell ausgewählt ist.
LittleFS verwendet die gleichen Partitionierungsschemata wie SPIFFS. Man muss also keine neuen Schemata erstellen, sondern nutzt die bereits für SPIFFS vorhandenen mit.
Ein erster Test: Belegung des Dateisystems anzeigen
Das folgende kleine Programm versucht, ein (bestehendes) LittleFS-Dateisystem zu öffnen. Wird kein Dateisystem gefunden, erfolgt ein zweiter Versuch – diesmal mit der Option, das Dateisystem neu zu formatieren. Schlägt auch das fehl, wird das Programm beendet. Andernfalls wird die Belegung angezeigt (freie und belegte Bytes sowie ein Listing der evtl. vorhandenen Dateien).
Normalerweise kann man das Dateisystem gleich mit der Option öffnen, es bei Bedarf zu formatieren, wenn man weiß, dass das Programm es evtl. mit einer unformatierten Datenpartition zu tun bekommt (dabei wird ein mglw. vorhandenes anderes System wie SPIFFS überschrieben). Der hier gezeigte Ablauf ist komplizierter als nötig und dient nur zu Demonstrationszwecken.
Ein längeres Programm, das ein paar mehr Bibliotheksfunktionen nutzt und z.B. Dateien liest und schreibt, folgt weiter unten.
/* ------------------------------------------------------------
* Testprogramm für Dateisystem LittleFS
* (verwendet Code aus der Beispieldatei
* LittleFS_esp32\examples\LITTLEFS_test\LittleFS_test.ino)
*
* Programm stellt nur fest, ob das Dateisystem genutzt werden
* kann. Falls nein, wird es formatiert.
*
* Falls ein Zugriff möglich ist, wird die Belegung angezeigt.
*
* 2021-05-22 Heiko / unsinnsbasis.de
* ------------------------------------------------------------ */
/* ------------------------------------------------------------
* Einbinden der benötigten Bibliotheken,
* Defintion von Konstanten,
* Anlegen der Datenobjekte
* ------------------------------------------------------------ */
// Übertragungsrate für Ausgabe zum seriellen Monitor
#define SERIAL_BAUDRATE 115200
#include <Arduino.h>
#include "FS.h"
#include <LITTLEFS.h>
/* ------------------------------------------------------------
* Liste aller Dateien und Unterverzeichnisse in einem
* Verzeichnis anzeigen
*
* Parameter:
* - Dateisystem (sollte LITTLEFS sein)
* - Verzeichnisname ("/" für das Root-Dir)
* - maximale Verzeichnistiefe
* ------------------------------------------------------------ */
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
Serial.printf("Directory-Listing: %s\r\n", dirname);
File root = fs.open(dirname);
if (!root) { // Verzeichnis nicht vorhanden
Serial.println("- Fehler beim Öffnen des Verzeichnisses");
return;
}
if (!root.isDirectory()) { // kein Verzeichnis, sondern Datei
Serial.println(" - kein Verzeichnis");
return;
}
File file = root.openNextFile();
// in einer Schleife durch die Liste aller vorhandenen
// Einträge gehen
while (file) {
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
// ist der Eintrag ein Verz., dann dessen Inhalt rekursiv
// anzeigen, wenn maximale Tiefe noch nicht erreicht ist
if (levels) {
listDir(fs, file.name(), levels-1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print("\tGröße: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
/* ------------------------------------------------------------ */
void setup() {
Serial.begin(SERIAL_BAUDRATE);
delay(500);
Serial.println("\n-------- LITTLEFS Test --------");
// versuchen, ein vorhandenes Dateisystem einzubinden
if (!LITTLEFS.begin(false)) {
Serial.println("LITTLEFS Mount fehlgeschlagen");
Serial.println("Kein Dateisystemsystem gefunden; wird formatiert");
// falls es nicht klappt, erneut mit Neu-Formatierung versuchen
if (!LITTLEFS.begin(true)) {
Serial.println("LITTLEFS Mount fehlgeschlagen");
Serial.println("Formatierung nicht möglich");
return;
} else {
Serial.println("Formatierung des Dateisystems erfolgt");
}
}
Serial.println("Informationen zum Dateisystem:");
Serial.printf("- Bytes total: %ld\n", LITTLEFS.totalBytes());
Serial.printf("- Bytes genutzt: %ld\n\n", LITTLEFS.usedBytes());
// Liste aller vorhandenen Dateien anzeigen
// (rekursiv bis zu 3 Verzeichnisebenen tief)
listDir(LITTLEFS, "/", 3);
}
void loop() {
// nichts tun
}
Ausgabe im seriellen Monitor:
-------- LITTLEFS Test -------- K:\code\arduino\libraries\LittleFS_esp32\src\lfs.c:1076:error: Corrupted dir pair at {0x16d, 0x16e} E (533) esp_littlefs: mount failed, (-84) E (534) esp_littlefs: Failed to initialize LittleFS LITTLEFS Mount fehlgeschlagen Kein Dateisystemsystem gefunden; wird formatiert K:\code\arduino\libraries\LittleFS_esp32\src\lfs.c:1076:error: Corrupted dir pair at {0x16d, 0x16e} E (554) esp_littlefs: mount failed, (-84) E (558) esp_littlefs: Failed to initialize LittleFS Formatierung des Dateisystems erfolgt Informationen zum Dateisystem: - Bytes total: 2031616 - Bytes genutzt: 8192 Directory-Listing: /
Man sieht
, dass die Formatierung erfolgreich war. Nach wenigen Sekunden steht ein leeres Dateisystem zur Verfügung, in dem zwei Blöcke (oder Sektoren) mit je 4096 Bytes für interne Zwecke des Dateisystems verwendet werden.
(Zum Testen kann man eine Neuformatierung auslösen, indem man im Menü Werkzeuge
das Partitionierungsschema wechselt, z.B. von »Default 4MB with spiffs(1.2MB APP/1.5MB SPIFFS)« zu »No OTA (2MB APP/2 MB SPIFFS)«. Da sich dabei auch die Größe der Programm-Partition ändert, muss man das Programm neu auf den ESP32 hochladen; ein einfacher Reset reicht nicht.)
Ist bereits ein LittleFS-Dateisystem vorhanden, wird sofort das Listing angezeigt:
-------- LITTLEFS Test -------- Informationen zum Dateisystem: - Bytes total: 2031616 - Bytes genutzt: 8192 Directory-Listing: /
Teil 2: Dateisystem-Tools (optional)
Der zweite Teil des Beitrags beschreibt die Installation der Dateisystem-Tools und flasht ein Dateisystem mit vorinstallierten Dateien auf den ESP32.
Programm zur Demonstration der Bibliotheksfunktionen
Das Programm demonstriert die Basisfunktionen, die man z.B. braucht, wenn man Sensordaten auslesen und speichern will. Viel mehr als das Anlegen und Ergänzen, bei Bedarf auch Löschen von Dateien, ist dazu erstmal nicht nötig. Wenn man tiefer einsteigen will, sind unten einige Dokumentations-Seiten verlinkt.
Die im Programm verwendeten Funktionen sind im Wesentlichen aus dem Beispielprogramm LittleFS_test.ino
der LittleFS-Bibliothek übernommen (Menü Datei → Beispiele / Beispiele aus eigenen Bibliotheken → LittleFS_esp32 → LITTLEFS_test
). Ich habe Kommentare ergänzt, sodass das Programm hoffentlich selbsterklärend ist.
Die Programmlogik baut zwar auf dem Beispiel-Dateisystem aus Teil 2 mit ein paar vorinstallierten Dateien auf, funktioniert aber auch mit einem leeren Dateisystem (manche Ausgaben sehen dann anders aus). Man muss also die Dateisystem-Tools nicht installieren.
/* ------------------------------------------------------------
* Testprogramm für Dateisystem LittleFS
* (verwendet Code aus der Beispieldatei
* LittleFS_esp32\examples\LITTLEFS_test\LittleFS_test.ino)
*
* - Liste der vorhandenen Dateien anzeigen
* - Dateiinhalt anzeigen
* - Anlegen eines Verzeichnisses
* - Schreiben von Daten in eine neue Datei, weitere Daten anhängen
* - Datei und Verzeichnis löschen
*
* 2021-05-21 Heiko / unsinnsbasis.de
* ------------------------------------------------------------ */
/* ------------------------------------------------------------
* Einbinden der benötigten Bibliotheken,
* Defintion von Konstanten,
* Anlegen der Datenobjekte
* ------------------------------------------------------------ */
// Übertragungsrate für Ausgabe zum seriellen Monitor
#define SERIAL_BAUDRATE 115200
#include <Arduino.h>
#include "FS.h"
#include <LITTLEFS.h>
// Dateisystem automatisch formatieren (true/false)
// (ist nicht nötig, wenn es mit ESP32FS (ESP32 Sketch
// Data Upload) erstellt wurde)
#define FORMAT_LITTLEFS_IF_FAILED true
/* ------------------------------------------------------------
* Liste aller Dateien und Unterverzeichnisse in einem
* Verzeichnis anzeigen
*
* Parameter:
* - Dateisystem (sollte LITTLEFS sein)
* - Verzeichnisname ("/" für das Root-Dir)
* - maximale Verzeichnistiefe
* ------------------------------------------------------------ */
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
Serial.printf("Directory-Listing: %s\r\n", dirname);
File root = fs.open(dirname);
if (!root) { // Verzeichnis nicht vorhanden
Serial.println("- Fehler beim Öffnen des Verzeichnisses");
return;
}
if (!root.isDirectory()) { // kein Verzeichnis, sondern Datei
Serial.println(" - kein Verzeichnis");
return;
}
File file = root.openNextFile();
// in einer Schleife durch die Liste aller vorhandenen
// Einträge gehen
while (file) {
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
// ist der Eintrag ein Verz., dann dessen Inhalt rekursiv
// anzeigen, wenn maximale Tiefe noch nicht erreicht ist
if (levels) {
listDir(fs, file.name(), levels-1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print("\tGröße: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
/* ------------------------------------------------------------
* Daten in eine Datei schreiben
* - existiert die Datei, wird sie überschrieben (Modus FILE_WRITE)
* oder die Daten werden angehängt (Modus FILE_APPEND)
*
* Parameter:
* - Dateisystem (sollte LITTLEFS sein)
* - Dateiname (vollständige Pfadangabe)
* - zu schreibende Daten (als Zeichenkette)
* - Modus zum Öffnen (FILE_WRITE oder FILE_APPEND)
* ------------------------------------------------------------ */
void writeFile(fs::FS &fs,
const char * path,
const char * message,
const char * mode) {
Serial.printf("Schreibe Datei: %s\r\n", path);
if (mode != FILE_WRITE && mode != FILE_APPEND) {
Serial.println("- ungültiger Zugriffsmodus (WRITE/APPEND)");
}
File file = fs.open(path, mode);
if (!file) {
Serial.println("- kann Datei nicht zum Schreiben öffnen");
return;
}
if (file.print(message)) {
if (mode == FILE_WRITE) {
Serial.println("- Datei neu geschrieben");
} else {
Serial.println("- Daten an Datei angehängt");
}
} else {
Serial.println("- Schreiben fehlgeschlagen");
}
file.close();
}
/* ------------------------------------------------------------
* Inhalt einer (Text-)Datei ausgeben
*
* Parameter:
* - Dateisystem (sollte LITTLEFS sein)
* - Dateiname (vollständige Pfadangabe)
* ------------------------------------------------------------ */
void readFile(fs::FS &fs, const char * path) {
Serial.printf("Lese Datei: %s\r\n", path);
File file = fs.open(path);
if (!file || file.isDirectory()) {
Serial.println("- kann Datei nicht zum Lesen öffnen");
return;
}
Serial.println("- lese Datei:");
while(file.available()) {
// Dateiinhalt Zeichen für Zeichen lesen und ausgeben
Serial.write(file.read());
}
file.close();
}
/* ------------------------------------------------------------
* Datei löschen
*
* Parameter:
* - Dateisystem (sollte LITTLEFS sein)
* - Dateiname (vollständige Pfadangabe)
* ------------------------------------------------------------ */
void deleteFile(fs::FS &fs, const char * path) {
Serial.printf("Lösche Datei: %s\r\n", path);
if (fs.remove(path)) {
Serial.println("- Datei gelöscht");
} else {
Serial.println("- Datei konnte nicht gelöscht werden");
}
}
/* ------------------------------------------------------------
* Verzeichnis anlegen
*
* Parameter:
* - Dateisystem (sollte LITTLEFS sein)
* - Verzeichnisname (vollständige Pfadangabe)
* ------------------------------------------------------------ */
void createDir(fs::FS &fs, const char * path) {
Serial.printf("Erstelle Verzeichnis: %s\n", path);
if (fs.mkdir(path)) {
Serial.println("Verzeichnis erstellt");
} else {
Serial.println("Erstellen des Verzeichnisses fehlgeschlagen");
}
}
/* ------------------------------------------------------------
* Verzeichnis löschen
*
* Parameter:
* - Dateisystem (sollte LITTLEFS sein)
* - Verzeichnisname (vollständige Pfadangabe)
* ------------------------------------------------------------ */
void removeDir(fs::FS &fs, const char * path) {
Serial.printf("Lösche Verzeichnis: %s\n", path);
if (fs.rmdir(path)) {
Serial.println("Verzeichnis gelöscht");
} else {
Serial.println("Fehler beim Löschen");
}
}
/* ------------------------------------------------------------ */
void setup() {
Serial.begin(SERIAL_BAUDRATE);
delay(500);
Serial.println("\n-------- LITTLEFS Test --------");
// Dateisystem einbinden
// (ggf. beim ersten Mal formatieren)
if(!LITTLEFS.begin(FORMAT_LITTLEFS_IF_FAILED)){
Serial.println("LITTLEFS Mount fehlgeschlagen");
return;
}
Serial.println("Informationen zum Dateisystem:");
Serial.printf("- Bytes total: %ld\n", LITTLEFS.totalBytes());
Serial.printf("- Bytes genutzt: %ld\n\n", LITTLEFS.usedBytes());
// Liste aller vorhandenen Dateien anzeigen
// (rekursiv bis zu 3 Verzeichnisebenen tief)
listDir(LITTLEFS, "/", 3);
Serial.println();
// Liste eines nicht vorhandenen Verz. anzeigen
// -> Fehlermeldung
listDir(LITTLEFS, "/unsinnsbasis", 3);
Serial.println();
// versuchen, einen Dateinamen als Verzeichnis anzuzeigen
// -> Fehlermeldung
listDir(LITTLEFS, "/testdatei.txt", 3);
Serial.println();
// Inhalt der Testdatei anzeigen
readFile(LITTLEFS, "/testdatei.txt");
Serial.println();
// bereits vorhandenes Verzeichnis nochmal erstellen
createDir(LITTLEFS, "/test-dir");
Serial.println();
// neues Verzeichnis anlegen
createDir(LITTLEFS, "/mein-directory");
Serial.println();
// dort eine Datei anlegen bzw. bei Vorhandensein überschreiben
writeFile(LITTLEFS, "/mein-directory/demo.dat",
"Das ist eine Demodatei\n", FILE_WRITE);
Serial.println();
// Liste der Dateien zeigt, ob Datei angelegt wurde
listDir(LITTLEFS, "/mein-directory", 1);
Serial.println();
writeFile(LITTLEFS, "/mein-directory/demo.dat",
"Mehr Daten", FILE_APPEND); // ohne Zeilenvorschub
Serial.println();
writeFile(LITTLEFS, "/mein-directory/demo.dat",
"Noch mehr Daten\n", FILE_APPEND);
Serial.println();
listDir(LITTLEFS, "/mein-directory", 1);
Serial.println();
readFile(LITTLEFS, "/mein-directory/demo.dat");
Serial.println();
// neu angelegtes Verzeichnis löschen
// -> Fehler, weil Verzeichnis nicht leer
removeDir(LITTLEFS, "/mein-directory");
// also Datei löschen und dann das Verzeichnis
deleteFile(LITTLEFS, "/mein-directory/demo.dat");
removeDir(LITTLEFS, "/mein-directory");
Serial.println();
// nach dem Aufräumen sollte es aussehen wie zu Beginn
listDir(LITTLEFS, "/", 1);
}
void loop() {
// nichts tun
}
Das Programm erzeugt folgende Ausgabe im seriellen Monitor:
-------- LITTLEFS Test --------
Informationen zum Dateisystem:
- Bytes total: 2031616
- Bytes genutzt: 16384
Directory-Listing: /
DIR : /test-dir
Directory-Listing: /test-dir
FILE: /test-dir/test2.txt Größe: 53
FILE: /testdatei.txt Größe: 52
Directory-Listing: /unsinnsbasis
- Fehler beim Öffnen des Verzeichnisses
Directory-Listing: /testdatei.txt
- kein Verzeichnis
Lese Datei: /testdatei.txt
- lese Datei:
Testdatei
Vom PC ins Dateisystem-Image übernommen.
Erstelle Verzeichnis: /test-dir
Verzeichnis erstellt
Erstelle Verzeichnis: /mein-directory
Verzeichnis erstellt
Schreibe Datei: /mein-directory/demo.dat
- Datei neu geschrieben
Directory-Listing: /mein-directory
FILE: /mein-directory/demo.dat Größe: 23
Schreibe Datei: /mein-directory/demo.dat
- Daten an Datei angehängt
Schreibe Datei: /mein-directory/demo.dat
- Daten an Datei angehängt
Directory-Listing: /mein-directory
FILE: /mein-directory/demo.dat Größe: 49
Lese Datei: /mein-directory/demo.dat
- lese Datei:
Das ist eine Demodatei
Mehr DatenNoch mehr Daten
Lösche Verzeichnis: /mein-directory
Fehler beim Löschen
Lösche Datei: /mein-directory/demo.dat
- Datei gelöscht
Lösche Verzeichnis: /mein-directory
Verzeichnis gelöscht
Directory-Listing: /
DIR : /test-dir
Directory-Listing: /test-dir
FILE: /test-dir/test2.txt Größe: 53
FILE: /testdatei.txt Größe: 52
Wenn man das Dateisystem mit den vorinstallierten Dateien nutzt, sieht man, dass das Erstellen des Verzeichnisses /test-dir
keine Fehlermeldung hervorruft (Zeilen 22/23 der Ausgabe), auch wenn es schon existiert. Das Ergebnis ist ja auch das gleiche: Nach dem Aufrufen der Funktion createDir()
existiert das Verzeichnis, unabhängig davon, ob es vorher schon da war oder nicht.
Außerdem muss man beim Schreiben der (Text-)Daten selbst an die Zeilenumbrüche denken – die Methode writeFile()
ergänzt sie nicht automatisch. In Programmzeile 229/230 wird der Text „Mehr Daten” ausgegeben. In Zeile 46 der Ausgabe sieht man, dass die nächsten Daten direkt angehängt wurden.
Die Angabe zu Beginn, dass die wenigen vorinstallierten Daten (2 Dateien mit jeweils nur etwas über 50 Bytes) 16 KB Platz belegen, mag erst einmal verwundern.[6]Bei einem anderen Test habe ich festgestellt, dass selbst das Anlegen eines leeren Verzeichnisses in einem neu initialisierten LittleFS-Dateisystem genausoviel Platz verbraucht. Sie relativiert sich schon etwas, wenn man den folgenden Hinweis kennt: »A freshly formatted LittleFS will have 2 blocks in use, making it seem like 8KB are in use.« Das zeigt auch die Belegung eines neu initialisierten LittleFS-Sytem im vorigen Beispiel – 8192 Bytes werden sofort vom Dateisystem selbst genutzt.
Außerdem kann LittleFS mehrere Dateien mit einer Größe bis 512 Bytes in einem Block zusammenlegen (siehe oben). In den momentan belegten Blöcken lassen sich also noch ein paar kleine Dateien zusätzlich unterbringen. Das macht sich aber bei zwei Dateien und einem Directory logischerweise kaum bemerkbar, sondern erst dann, wenn viele Dateien gespeichert sind. Der Overhead zur Verwaltung des Dateisystems wird dann im Verhältnis zu den Nutzdaten deutlich kleiner.
Weitere Dateisystem-Funktionen zeigt das Beispielprogramm LittleFS_test.ino
der LittleFS-Bibliothek. Das andere Beispiel LittleFS_time.ino
ist ähnlich und zeigt auch, wie man das Zugriffsdatum einer Datei ausliest; außerdem sieht man dort, wie einfach (zumindest in diesem Fall) die Umstellung des Programmcodes von SPIFFS auf LittleFS möglich ist.
Links
Es gibt noch keine offizielle Dokumentation von espressif oder den Enwicklern für die ESP32-Version von LittleFS.
- LittleFS-Bibliothek für den ESP32 in der Arduino-IDE: Beispielprogramme; insbes.
LITTLEFS_test.ino
zeigt die Nutzung aller Basisfunktionen - Dokumentation von espressif zu SPIFFS (espressif-IDE ESP-IDF)
- Dokumentation von espressif zu Dateisystemen für den ESP8266 – dort sieht man, wie SPIFFS und LittleFS auf dem ESP8266 programmiert werden.
- SPIFFS-Bibliothek im Arduino-Paket für den ESP32
Weiterführende Links:
- Homepage des LittleFS-Projekts: github.com/littlefs-project/littlefs/
- LittleFS für die ESP32-Entwicklungsumgebung von espressif (ESP-IDF): github.com/joltwallet/esp_littlefs
23.08.2021 Tippfehler korrigiert – auch in Kommentaren der Testprogramme
Fußnoten
1↑ | Das Arduino-Paket für den ESP32 befindet sich bei Github: github.com/espressif/arduino-esp32; wer die Entwicklerversion ausprobieren möchte, muss in der Boardverwaltung der Arduino-IDE folgende URL eintragen: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json |
---|---|
2↑ | Eigene Übersetzung: »SPIFFS wird derzeit als veraltet betrachtet und wird möglicherweise in zukünftigen Versionen des Kerns entfernt. Bitte denken Sie darüber nach, Ihren Code auf LittleFS umzustellen. SPIFFS wird vom ursprünglichen Entwickler nicht mehr aktiv unterstützt, während LittleFS aktiv entwickelt wird, echte Verzeichnisse unterstützt und bei den meisten Operationen um ein Vielfaches schneller ist.« |
3↑ | Komplettes Zitat von github.com/joltwallet/esp_littlefs (die Entwickler der LittleFS-Bibliothek für die ESP-IDF, die Grundlage der aktuellen ESP32-Bibliothek für die Arduino-IDE ist): »See the official ESP-IDF SPIFFS documentation, basically all the functionality is the same; just replace spiffs with littlefs in all function calls. Also see the comments in include/esp_littlefs.h Slight differences between this configuration and SPIFFS’s configuration is in the esp_vfs_littlefs_conf_t: max_files field doesn’t exist since we removed the file limit, thanks to @X-Ryl669 partition_label is not allowed to be NULL. You must specify the partition name from your partition table. This is because there isn’t a define littlefs partition subtype in esp-idf. The subtype doesn’t matter.« (Die erwähnte include-Datei esp_littlefs.h ist hier zu finden: github.com/joltwallet/esp_littlefs/blob/master/include/esp_littlefs.h.)Auch „lorol”, der Entwickler der ESP32-Bibliothek, schreibt in einem Forums-Beitrag: »Here’s my port of LittleFS that has the same API as the esp-idf SPIFFS port. Basically it should just work if you replace all your “spiffs” calls with “littlefs”. Only slight difference is in your configuration, you don’t specify “max_files”.« |
4↑ | Siehe github.com/joltwallet/esp_littlefs#documentation: »max_files field doesn’t exist since we removed the file limit«. In der Header-Datei LITTLEFS.h wird zwar beim Aufruf der begin -Methode die Anzahl 10 voreingestellt; das hat aber nur Kompatibiltätsgründe (siehe die Dokumentation der Bibliothek). |
5↑ | Welche Version man installiert hat, kann man in der Boardverwaltung überprüfen: Menü Werkzeuge → Board "xyz" → Boardverwalter… , dort im Suchfeld „esp” eingeben.Für Core-Version 1.0.4 sollte man den Kompatibilitäts-Hinweis zu CONFIG_LITTLEFS_FOR_IDF_3_2 hier oder im Quelltext beachten. |
6↑ | Bei einem anderen Test habe ich festgestellt, dass selbst das Anlegen eines leeren Verzeichnisses in einem neu initialisierten LittleFS-Dateisystem genausoviel Platz verbraucht. |
Themenverwandte Beiträge
Mit dem ADS1115 Breakout Board) ist es möglich, Analogwerte deutlich genauer zu messen, als es ein E...
Wie der HC-SR501 sind auch der HC-SR505, der AM312 und der SR602 pyroelektrische Infrarotsensoren (a...
Durch einen Artikel im Heise Newsticker bin ich auf den Longan Nano der chinesischen Firma Sipeed ge...
Der SHT20 ist ein weiterer Sensor zur Messung der Umgebungstemperatur und der relativen Luftfeuchtig...
Hallo und gutes, gesundes neues Jahr!
Ich bin von der darstellung des littlefs begeistert! gut und nachvollziehbar beschrieben und alles funktioniert sofort – respekt !!!
aber ich habe eine frage: ist es möglich auch daten abzuspeichern?
ich habe die daten mit memcpy in ein string-array umkopiert und dann lässt es sich in das file-system speichern. funktioniert solange bis eine wert ‘0’ ist. dann bricht das schreiben ab, weil ein text bekanntlich ‘0’-terminiert ist.
in der übergrabe-prozedur ist die ‘nutzlast’ als string formatiert. kann man das ‘ungestraft’ in ein byte-array umdefinieren? gibt es eine andere lösung?
gibt es interesse an einem pc-frontend in pure-basic? dran arbeite ich gerade….
vielen dank schonmal im voraus
mitarbeit möglich (dokumentation)?
schöne tage Gorch
Danke, hat mir sehr geholfen.