ESP32. Débuter avec la librairie SPIFFS.h pour lire, écrire, modifier des fichiers • Domotique et objets connectés à faire soi-même

SPIFFS (Serial Peripheral Interface Flash File System) est un système de fichiers léger adapté (entre autre) aux micro-contrôleurs disposant d’une mémoire flash SPI tel que l’ESP32 et ESP8266. La librairie Arduino SPIFFS.h permet d’accéder à la mémoire flash comme s’il s’agissait d’un système de fichiers normal comme celui d’un ordinateur (en bien plus simple évidemment). On pourra lire, écrire et ajouter des données à un fichier et réaliser quelques opérations simples (formater, renommer, récupérer des informations…)

Présentation du système de fichier SPIFFS (SPI Flash File System)

SPIFFS (pour Serial Peripheral Interface Flash File System) est un système de fichier développé par Peter Andersson (page du projet sur GitHub) qui peut fonctionner sur n’importe quel mémoire flash NOR ou flash SPI.

La librairie développée pour les modules ESP8266 reprend l’essentiel des fonctionnalités avec quelques limitations supplémentaires du fait des limitations des micro-contrôleurs :

  • Arborescence il n’y a pas d’arborescence de fichier. Les fichiers sont placés à plat dans la zone de fichier. A la place, il est possible d’utiliser le caractère “\” dans le nom de fichier pour créer une pseudo arborescence.
  • Nom de fichier limité à 31 caractères utiles c’est la seconde limitation importante. 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.
  • Pas de message d’alerte en cas d’erreur aucun message d’erreur n’apparaîtra à la compilation ou à l’exécution si la limites de 32 caractères est dépassée. Si le programme ne fonctionne pas comme prévu, pensez à vérifier le nom de fichier.

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
  • Il n’y a pas de file d’attente
  • Le temps d’écriture est variable d’un fichier à l’autre
  • SPIFFS est destiné aux petits périphériques à mémoire flash, ne dépassez pas 128 Mo de stockage
  • Il n’y a pas de mécanisme de détection de blocs défectueux

Découverte de la librairie SPIFFS.h, API et méthodes disponibles

La librairie SPIFFS.h est un portage de la librairie officielle pour Arduino qui est installée en même temps que le SDK ESP32.

Les méthodes proposées sont quasiment identiques à la librairie FS.h pour ESP8266.

Les méthodes suivantes ne sont pas disponibles

API librairie FS.h Méthode équivalente
SPIFFS.openDir(chemin) aucune
SPIFFS.info(fs_info) SPIFFS.totalBytes()

Renvoie le nombre total d’octets utilisés par le système de fichier SPIFFS.

SPIFFS.usedBytes()

Renvoie l’espace utilisé par le fichier spécifié en octets

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

#include "SPIFFS.h"

Comment formatter un nom (chemin) de fichier ?

SPIFFS ne gère pas l’arborescence.

On pourra toutefois créer une pseudo arborescence en utilisant le caractère “/” dans le nom de fichier sans dépasser la limite de 31 caractères utiles.

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

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

SPIFFS.begin()

Cette méthode monte le système de fichiers SPIFFS 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 SPIFFS file system | Démarre le système de fichier SPIFFS 
  if(!SPIFFS.begin()){ 
    Serial.println("An Error has occurred while mounting SPIFFS");  
  }
}

SPIFFS.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.

if (!SPIFFS.begin(true)) {
    Serial.println("An Error has occurred while mounting SPIFFS");
  return;
}

bool formatted = SPIFFS.format();
 if ( formatted ) {
  Serial.println("SPIFFS formatted successfully");
} else {
  Serial.println("Error formatting");
}

SPIFFS.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. Attention, il n’est pas possible de connaître la taille d’un dossier

File file = SPIFFS.open("/test.txt"); 
if(!file){ 
  Serial.println("Failed to open file for reading"); 
  return; 
} 
Serial.print("File size: "); 
Serial.println(file.size()); 
file.close();

file.name()

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

file.close()

Ferme le fichier

Opérations sur les dossiers

file.isDirectory()

Il n’y a pas de différence entre fichier et dossier. La méthode isDirectory() permet de savoir si le fichier est un dossier. Il n’est pas possible de connaître la taille d’un dossier

dir.openNextFile()

Ouvre le dossier suivant

SPIFFS.exists(chemin)

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

SPIFFS.totalBytes()

Renvoie le nombre total d’octets utilisés par le système de fichier SPIFFS.

SPIFFS.usedBytes()

Renvoie l’espace utilisé par le fichier spécifié en octets

SPIFFS.remove(chemin)

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

SPIFFS.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.

SPIFFS.end()

Démonte le système de fichier

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

Il est possible de téléverser directement des fichiers dans le système de fichier SPIFFS à l’aide du plugin pour l’IDE Arduino ESP32 Sketch Data Upload.

ev4msxglcijlnrcgwdjt-5340308

Pour cela, il suffit de créer un dossier nommé data au même niveau que le fichier principal du projet Arduino. Il est préférable d’éviter de créer des sous-dossiers.

En effet, le système de fichier SPIFFS ne gère pas l’arborescence de fichier. Lors du transfert, les fichiers seront mis “à plat”, c’est à dire que le fichier prendra comme nom le chemin d’accès.

utr4mxtnx4syntxmhxqx-3459134

Pour en savoir plus, lisez ce tutoriel qui explique tout en détail.

Récupérer les informations de la zone SPIFFS 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 présents dans la zone mémoire.

#include "SPIFFS.h" 

void listFilesInDir(File dir, int numTabs = 1);

void setup() {
    Serial.begin(112500);
 
    delay(500);
 
    Serial.println(F("Inizializing FS..."));
    if (SPIFFS.begin()){
        Serial.println(F("SPIFFS mounted correctly."));
    }else{
        Serial.println(F("!An error occurred during SPIFFS mounting"));
    }

    // Get all information of SPIFFS
 
    unsigned int totalBytes = SPIFFS.totalBytes();
    unsigned int usedBytes = SPIFFS.usedBytes();
 
    Serial.println("===== File system info =====");
 
    Serial.print("Total space:      ");
    Serial.print(totalBytes);
    Serial.println("byte");
 
    Serial.print("Total space used: ");
    Serial.print(usedBytes);
    Serial.println("byte");
 
    Serial.println();
 
    // Open dir folder
    File dir = SPIFFS.open("/");
    // List file at root
    listFilesInDir(dir);
}

void listFilesInDir(File dir, int numTabs) {
  while (true) {
 
    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files in the folder
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      listFilesInDir(entry, numTabs + 1);
    } else {
      // display zise for file, nothing for directory
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

void loop() {
 
} 

Ouvrez le Moniteur série pour visualiser l’occupation, l’espace disponible est les fichiers SPIFFS stockés sur la mémoire flash.

Inizializing FS...
SPIFFS mounted correctly.
File system info.
Total space:      1374476byte
Total space used: 502byte

    /test.txt       11

Comment écrire dans un fichier par programmation avec SPIFFS.h

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

La librairie SPIFFS.h met à disposition plusieurs méthodes simples pour accéder et manipuler les fichiers depuis un programme Arduino. Vous pouvez utiliser toutes les méthodes listées précédemment.

Ajouter ce code juste après le ligne file.close();

file = SPIFFS.open("/test.txt", "w");
if(!file){
  // File not found | le fichier de test n'existe pas
  Serial.println("Failed to open test file");
  return;
} else {
  file.println("Hello From ESP32 :-)");
  file.close();
}

Que fait ce code ?

Cette fois, on ouvre le fichier avec l’option “w” pour indiquer qu’on souhaite modifier le fichier. Le contenu précédent sera effacé

Pour écrire dans un fichier, on peut utiliser les méthodes 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.

Ici, on actualise le contenu précédent

file.println("Hello From ESP32 :-)");

Téléverser pour visualiser ce qui se passe

Comment ajouter des données à un fichier par programmation ?

Pour ajouter des données à un fichier, il suffit d’ouvrir de fichier avec l’option “a” (append) pour ajouter des données à la fin du fichier.

Si le fichier n’existe pas, il sera automatiquement créé.

Voici un petit exemple qui enregistre un compteur chaque seconde.

void loop(){
  File file = SPIFFS.open("/counter.txt", "a");
  if(!file){
    // File not found | le fichier n'existe pas
    Serial.println("Failed to open counter file");
    return;
  } else {
    counter+=1;
    file.println(counter);
    file.close();
  }
  delay(1000);
}

Mises à jour

02/09/2020 Première publication de l’article

Avez-vous aimé cet article ?