ESP8266. Utiliser la librairie LittleFS pour lire, écrire, modifier des fichiers • Domotique et objets connectés à faire soi-même

LittleFS est un système de fichier sécurisé spécialement conçu pour les micro-contrôleurs. C’est le successeur de la librairie FS.h prenant en charge SPIFFS (Serial Peripheral Interface Flash File System). On pourra lire, écrire et ajouter des données à un fichier et réaliser quelques opérations simples. LittleFS prend en charge l’arborescence de fichier.

Présentation du système de fichier LittleFS

La librairie LittleFS vient remplacer la librairie SPIFFS. Elle offre des performances supérieures et la prise en charge des répertoires.

LittleFS pour l’ESP8266 prend en charge les noms de fichiers jusqu’à 31 caractères utiles se terminant par zéro (c’est-à-dire char filename [32]) avec autant de sous-répertoires que l’espace le permet.

  • Arborescence il est possible de créer des sous-dossiers arborescence de fichier.
  • Nom de fichier est limité à 31 caractères utiles  Le caractère ‘\0’ est réservé et automatiquement ajouté à la fin du nom de fichier pour la compatibilité avec les chaînes de caractère du langage C. Attention, l’extension de fichier consomme en général 4 caractères sur les 31 utiles.
  • Le nombre de caractères correspond au chemin complet incluant le nom du fichier et son extension.
  • Résilience à la perte de puissance. LittleFS est conçu pour gérer les pannes de courant aléatoires y compris durant les opérations d’écriture.
  • Gestion des blocs mémoire défectueux LittleFS peut détecter les blocs défectueux et les contourner.
  • RAM / ROM limitée. LittleFS est conçu pour fonctionner avec une petite quantité de mémoire. L’utilisation de la RAM est strictement limitée, ce qui signifie que la consommation de RAM ne change pas à mesure que le système de fichiers se développe. Le système de fichiers ne contient pas de récursivité illimitée car la mémoire utilisée par LittleFS est réservée de manière statique.

Autres limitations utiles à connaître :

  • Il ne faut pas utiliser d’espace(s) ou de caractère(s) accentué(s) dans le nom de fichier

Plus d’informations sur LittleFS sur GitHub ici.

Découverte de la librairie LittleFS, API et méthodes disponibles

La librairie LittleFS est installée en même temps que le SDK ESP8266. Toutes les méthodes proposées par la librairie LittleFS sont très bien documentées ici.

Pour accéder au système de fichier, il suffit de la déclarer au début du croquis

#include "LittleFS.h"

Comment formatter un nom (chemin) de fichier ?

LittleFS gère l’arborescence de fichier dans la limite de 31 caractères utiles en incluant le nom du fichier et son extension.

dossier/ssdossier/fichier1.text
|——— 31 caractères ———|

Le chemin de fichier doit toujours commencer par le caractère “/”, par exemple /fichier.txt

Les méthodes (API) de la librairie LittleFS.h

LittleFS.begin()

Cette méthode monte le système de fichiers LittleFS et doit être appelée avant que n’importe quelle autre méthode FS ne soit utilisée. Renvoie true si le système de fichiers a été monté avec succès.

Il est conseillé de monter le système de fichier dans le setup

void setup() { 
  // Launch LittleFS file system | Démarre le système de fichier LittleFS 
  if(!Little.begin()){ 
    Serial.println("An Error has occurred while mounting LittleFS");  
  }
}

LittleFS.format()

Formate le système de fichier. Renvoie true si le formatage a réussi. Attention, si des fichiers sont présents dans la zone mémoire, ils seront supprimés de façon irréversible.

LittleFS.open(path, option)

Ouvre un fichier

path doit être un chemin absolu commençant par une barre oblique (par exemple /dir/nom_fichier.txt).

option est une chaîne spécifiant le mode d’accès. Il peut s’agir de

  • “r” read, lecture seule
  • “r+” lecture et écriture. Le pointeur est positionné au début du fichier
  • “w” write, écriture. Le contenu existant est supprimé. Le fichier est créé s’il n’existe pas
  • “w+” ouvre le fichier en lecture et à l’écriture. Le fichier est créé s’il n’existe pas, sinon il est tronqué. Le pointeur est positionné au début du fichier
  • “a” append, ouvre un fichier en ajout de données. Le fichier est créé s’il n’existe pas. Le pointeur est positionné à la fin du fichier s’il existe déjà
  • “a+” append, ouvre un fichier en ajout de données. Le fichier est créé s’il n’existe pas. La pointeur est positionné au début du fichier en lecture et à la fin du fichier pour l’écriture (ajout)

Renvoie l’objet File. Pour vérifier si le fichier a été ouvert avec succès, utilisez l’opérateur booléen.

Une fois que le fichier est ouvert, voici les méthodes qui permettent de le manipuler

file.seek(décalage, mode)

Cette fonction se comporte comme la fonction fseek du langage C. En fonction de la valeur de mode, le pointeur est positionné dans le fichier comme ceci

SeekSet la position est définie pour décaler les octets par rapport au début
SeekCur la position actuelle est déplacée par octets de décalage
SeekEnd la position est définie pour décaler les octets à partir de la fin du fichier

La fonction renvoie true si la position a été définie avec succès

file.position()

Renvoie la position actuelle dans le fichier en octets.

file.size()

Renvoie la taille du fichier en octets.

file.name()

Renvoie le nom du fichier dans une constante au format const char *.

file.close()

Ferme le fichier

LittleFS.exists(chemin)

Renvoie true si un fichier avec un chemin donné existe, false dans le cas contraire.

LittleFS.openDir(chemin)

Ouvre un répertoire en fonction de son chemin absolu. Renvoie un objet Dir

La liste de méthodes permettant de gérer les dossiers est ici

LittleFS.mkdir(chemin)

Créer un nouveau dossier. Renvoie true si la création du répertoire a réussi

LittleFS.rmdir(chemin)

Supprimer le répertoire. Renvoie true si le répertoire a été supprimé avec succès

LittleFS.remove(chemin)

Supprime le fichier en fonction de son chemin absolu. Renvoie true si le fichier a été supprimé avec succès

LittleFS.rename(pathFrom, pathTo)

Renomme le fichier de pathFrom à pathTo. Les chemins doivent être absolus. Renvoie true si le fichier a été renommé avec succès

LittleFS.info(fs_info)

Remplit la structure FSInfo avec des informations sur le système de fichiers. Renvoie vrai en cas de succès.

LitteFS.end()

Démonte le système de fichier

Méthodes pour gérer les dossiers

Les dossiers sont traités comme des fichiers, on peut utiliser la plupart des méthodes destinées aux fichiers sur les dossiers. Pour savoir si le fichier ouvert est un dossier, on dispose de la méthode isDirectory() qui renvoie vrai ou faux.

Le choix est un peu perturbant mais c’est un compromis pour limiter la taille de la librairie, on est sur un micro-contrôleur.

LittleFS.openDir(path)

Ouvre le répertoire indiqué par path. Le chemin doit être absolu et commencer par “/”.

Renvoie un objet Dir. Un pointeur interne est positionné sur le premier fichier. On pourra utiliser les méthode suivantes sur l’objet dir.

Méthodes pour se déplacer dans un dossier

dir.next()

Renvoie true tant qu’il y a des fichiers dans le répertoire à parcourir. Il doit être appelé avant d’appeler les fonctions fileName(), fileSize() et openFile()

dir.rewind()

Renvoi le pointeur interne au début du répertoire

Méthodes pour collecter des informations sur un dossier

dir.openFile()

Cette méthode fonctionne à l’identique que LittleFS.open()

dir.fileName()

Renvoie le nom du dossier

dir.fileSize()

Renvoie la taille du fichier actuel

dir.fileTime()

Renvoie l’heure d’écriture time_t du fichier courant

dir.fileCreationTime()

Renvoie l’heure de création time_t du fichier actuel

dir.isFile()

Renvoie true si c’est un fichier.

dir.isDirectory()

Renvoie true si c’est un répertoire.

Comment convertir du code SPIFFS en LittleFS ?

Les développeurs de LittleFS ont eut la bonne idée de conserver la même API que la librairie FS.h de SPIFFS.

Il suffira d’utiliser l’outil de recherche de l’IDE Arduino pour replacer toutes les chaînes de code commençant par SPIFFS en LittleFS.

On retrouve toutes les méthodes proposées par SPIFFS, LittleFS ajoute des méthodes supplémentaires pour :

  • Se déplacer dans l’arborescence (qui n’est pas gérée par SPIFFS) : LittleFS.openDir(), dir.openFile(), dir.next(), dir.rewind()
  • Récupérer des informations sur les répertoires : dir.fileName(), dir.fileSize(), dir.fileTime(), dir.fileCreationTime(), dir.isFile(), dir.isDirectory()
  • Gérer les répertoires : LittleFS.mkdir(chemin), LittleFS.rmdir(chemin)

Comment transférer des fichiers dans la zone mémoire LittleFS ?

Il est possible de téléverser directement des fichiers dans le système de fichier LittleFS depuis un ordinateur à l’aide du plugin pour l’IDE Arduino ESP8266 LittleFS Data Upload. La procédure d’installation est détaillée dans ce tutoriel.

Voici un exemple d’organisation de fichier d’un projet ESP8266. Il faudra au préalable créer un dossier data au même niveau que le programme Arduino (fichier ino).

Après chaque modification ou ajout d’un fichier dans le dossier data – ou avant le premier démarrage du projet sur l’ESP8266 – il faudra téléverser manuellement les fichiers depuis le menu Outils -> ESP8266 LittleFS Data Upload.

Récupérer les informations de la zone LittleFS et la liste des fichiers

Voici un petit exemple de code qui permet de récupérer les informations de la zone mémoire ainsi que la liste des fichiers. Attention, l’exploration des sous-dossiers n’est pas récursive.

#include "LittleFS.h"

void setup()
{
  Serial.begin(112500);
  Serial.println("");

  Serial.println(F("Initializing FS..."));
  if (LittleFS.begin()) {
    Serial.println(F("LittleFS system mounted with success"));
  } else {
    Serial.println(F("An Error has occurred while mounting LittleFS"));
  }

  // Get all information about LittleFS
  FSInfo fsInfo;
  LittleFS.info(fsInfo);

  Serial.println("------------------------------");
  Serial.println("File system info");
  Serial.println("------------------------------");
  
  // Taille de la zone de fichier
  Serial.print("Total space:      ");
  Serial.print(fsInfo.totalBytes);
  Serial.println(" byte");

  // Espace total utilise
  Serial.print("Total space used: ");
  Serial.print(fsInfo.usedBytes);
  Serial.println(" byte");

  // Taille d un bloc et page
  Serial.print("Block size:       ");
  Serial.print(fsInfo.blockSize);
  Serial.println(" byte");

  Serial.print("Page size:        ");
  Serial.print(fsInfo.totalBytes);
  Serial.println(" byte");

  Serial.print("Max open files:   ");
  Serial.println(fsInfo.maxOpenFiles);

  // Taille max. d un chemin
  Serial.print("Max path lenght:  ");
  Serial.println(fsInfo.maxPathLength);

  Serial.println();

  Serial.println("------------------------------");
  Serial.println("List files");
  Serial.println("------------------------------");
  // Ouvre le dossier racine | Open folder
  Dir dir = LittleFS.openDir("/");
  // Affiche le contenu du dossier racine | Print dir the content
  while (dir.next()) {
    // recupere le nom du fichier | get filename
    Serial.print(dir.fileName());
    Serial.print(" - ");
    // et sa taille | and the size
    if (dir.fileSize()) {
      File file = dir.openFile("r");
      Serial.print(file.size());
      Serial.println(" byte");
      file.close();
    } else {
      File file = dir.openFile("r");
      if ( file.isDirectory() ) {
        Serial.println("this is a folder");
      } else {
        Serial.println("file is empty");
      }
      file.close();
    }
  }
}

void loop() {
}

N’oubliez pas de téléverser les fichiers avant ou après avoir de compilé le code

Comment manipuler un fichier par programmation avec LittleFS.h

On a vu comment créer un fichier depuis un ordinateur puis le téléverser depuis l’IDE Arduino.

Voici un petit exemple qui montre comment lire et écrire dans un fichier avec la libraire LittleFS.

#include "LittleFS.h"

void setup() {
  Serial.begin(115200);
  Serial.println("");
  // Launch LittleFS file system | Démarre le système de fichier LittleFS
  if(!LittleFS.begin()){
    Serial.println("An Error has occurred while mounting LittleFS");
    return;
  }
  
  File file = LittleFS.open("/demo.txt", "w");
  if (file) {
    // Remplace le contenu du fichier deom.txt, un nouveau fichier est créé s'il n'existe pas
    Serial.println("Write content to file. Create the file if not exist");
    file.print("A content create with LittleFS library !!");
    file.close();
  } else {
    Serial.println("Problem on create file!");
  }
  
  // On verifie si le fichier a ete correctement cree
  file = LittleFS.open("/demo.txt", "r");
  if (!file) {
    // File not found | le fichier de test n'existe pas
    Serial.println("Failed to open test file");
  } else {
    // Display file content on serial port | Envoie le contenu du fichier test sur le port série
    Serial.println();
    Serial.println("Read demo.txt file content: ");
    while (file.available()) {
      Serial.write(file.read());
    }
  }

  file.close();
}

void loop() {
}

Que fait ce code ?

On ouvre le fichier avec l’option “w” pour indiquer qu’on souhaite pouvoir écrire dans le fichier. Le contenu précédent sera effacé

File file = LittleFS.open("/demo.txt", "w");

On test l’objet file.

if (file) {
  // Le fichier existe ou le disque LittleFS a bien été monté
} else {
  // Il y a un problème avec LittleFS (ou avec le fichier), vérifiez que la méthode begin() a bien été appelée avant
}

On écrit du texte dans le fichier avec la commande print() ou println(). La méthode println() ajoute un retour à la ligne. On l’utilisera pour créer un tableau de données par exemple.

file.print("A content create with LittleFS library !!");

Il est préférable de fermer le fichier dès qu’il n’est plus utilisé

file.close();

Mises à jour

14/08/2020 Première publication de l’article

Avez-vous aimé cet article ?

[Total: 2 Moyenne: 5]