Contactez-nous

Création, suppression et renommage de fichiers et de répertoires

Apprenez a creer (mkdir), supprimer (rm, rmdir, unlink) et renommer (rename) des fichiers et des repertoires avec le module fs de Node.js (async/sync).

Manipuler la structure du systeme de fichiers

Au-delà de la simple lecture et écriture du contenu des fichiers, une application Node.js a souvent besoin de manipuler la structure même du système de fichiers. Cela inclut la création de nouveaux répertoires pour organiser les données, le renommage de fichiers ou de dossiers pour refléter des changements d'état, et la suppression d'éléments devenus obsolètes ou temporaires. Le module `fs` offre un ensemble complet de fonctions pour réaliser ces opérations de gestion.

Comme pour les opérations de lecture/écriture, ces fonctions de manipulation de structure existent en versions asynchrones (avec callbacks ou promesses) et synchrones. Nous continuerons de privilégier l'approche asynchrone, notamment avec `fs.promises`, pour maintenir la performance et la réactivité des applications, tout en mentionnant les équivalents synchrones pour information ou pour des cas d'usage spécifiques (scripts d'initialisation).

Creation de repertoires : `mkdir`

Pour créer un nouveau répertoire (dossier), la fonction principale est `fs.mkdir()` ou sa version promesse `fs.promises.mkdir()`. Par défaut, elle crée un seul répertoire et échoue si le répertoire parent n'existe pas.

Signature de la version promesse :

fs.promises.mkdir(path, [options])
  • path : Le chemin du répertoire à créer.
  • options (optionnel) : Un objet, dont l'option la plus importante est recursive (booléen). Si `recursive: true`, `mkdir` créera les répertoires parents nécessaires (similaire à `mkdir -p` en ligne de commande). Une autre option est `mode` pour définir les permissions (par défaut `0o777`).

Exemple de création de répertoire (simple et récursif) :

const fs = require('fs').promises;

async function createDirectories() {
  try {
    // Créer un seul répertoire (échoue si 'data' existe déjà)
    await fs.mkdir('data');
    console.log('Répertoire \'data\' créé.');

    // Créer une structure imbriquée (ne lève pas d'erreur si existe déjà)
    await fs.mkdir('uploads/images/avatars', { recursive: true });
    console.log('Structure \'uploads/images/avatars\' créée (ou déjà existante).');

  } catch (err) {
    // Gérer les erreurs (ex: EEXIST si le répertoire existe déjà et recursive: false)
    if (err.code !== 'EEXIST') {
        console.error('Erreur lors de la création de répertoire(s):', err);
    }
     else {
        console.log('Répertoire \'data\' existe déjà (erreur EEXIST ignorée).');
    }
  }
}

createDirectories();

La version synchrone est `fs.mkdirSync(path, [options])`.

Renommer ou deplacer : `rename`

La fonction `fs.rename()` (et `fs.promises.rename()` / `fs.renameSync()`) sert à la fois à renommer un fichier ou un répertoire et à le déplacer vers un autre emplacement sur le même système de fichiers (même volume/partition). L'opération est généralement atomique au niveau du système de fichiers.

Signature de la version promesse :

fs.promises.rename(oldPath, newPath)
  • oldPath : Le chemin actuel du fichier ou répertoire.
  • newPath : Le nouveau chemin souhaité.

Exemple de renommage et de déplacement :

const fs = require('fs').promises;

async function manageFiles() {
  try {
    // Supposons qu'un fichier temporaire existe
    await fs.writeFile('temp_report.tmp', 'Contenu temporaire');

    // 1. Renommer le fichier
    await fs.rename('temp_report.tmp', 'final_report.txt');
    console.log('Fichier renommé en final_report.txt');

    // 2. Déplacer le fichier dans un autre répertoire (qui doit exister)
    await fs.mkdir('archives', { recursive: true }); // S'assurer que le répertoire existe
    await fs.rename('final_report.txt', 'archives/report_2023.txt');
    console.log('Fichier déplacé vers archives/report_2023.txt');

  } catch (err) {
    console.error('Erreur lors du renommage/déplacement:', err);
  }
}

manageFiles();

Attention, `rename` échoue si `newPath` existe déjà (sauf sur certains systèmes et cas spécifiques). Il ne peut pas non plus déplacer des fichiers entre différents systèmes de fichiers (volumes) ; dans ce cas, il faudrait copier puis supprimer l'original.

Pour supprimer un fichier (et non un répertoire), on utilise `fs.unlink()` (ou `fs.promises.unlink()` / `fs.unlinkSync()`). Son nom vient de l'appel système Unix qui supprime un lien vers un fichier.

Signature de la version promesse :

fs.promises.unlink(path)
  • path : Le chemin du fichier à supprimer.

Exemple :

const fs = require('fs').promises;

async function cleanupTempFile(filePath) {
  try {
    await fs.unlink(filePath);
    console.log(`Fichier temporaire ${filePath} supprimé.`);
  } catch (err) {
    // Gérer les erreurs, notamment ENOENT si le fichier n'existe déjà plus
    if (err.code === 'ENOENT') {
      console.log(`Le fichier ${filePath} n'existe pas/plus.`);
    } else {
      console.error(`Erreur lors de la suppression de ${filePath}:`, err);
    }
  }
}

// Supprimer un fichier potentiellement créé précédemment
cleanupTempFile('archives/report_2023.txt');

Suppression de repertoires vides : `rmdir`

Pour supprimer un répertoire vide, la fonction historique est `fs.rmdir()` (ou `fs.promises.rmdir()` / `fs.rmdirSync()`).

Signature de la version promesse :

fs.promises.rmdir(path, [options])
  • path : Le chemin du répertoire vide à supprimer.
  • options (optionnel) : Peut inclure `maxRetries` et `retryDelay` en cas d'erreur `EBUSY` ou `ENOTEMPTY` (rarement utilisé). Attention : `rmdir` ne dispose pas d'option `recursive` pour supprimer des répertoires non vides.

Exemple :

const fs = require('fs').promises;

async function removeEmptyDirectory(dirPath) {
  try {
    await fs.rmdir(dirPath);
    console.log(`Répertoire vide ${dirPath} supprimé.`);
  } catch (err) {
    // Gérer les erreurs : ENOENT (n'existe pas), ENOTEMPTY (non vide), EACCES (permissions)
    if (err.code === 'ENOENT') {
        console.log(`Le répertoire ${dirPath} n'existe pas.`);
    } else if (err.code === 'ENOTEMPTY') {
        console.log(`Le répertoire ${dirPath} n'est pas vide.`);
    } else {
        console.error(`Erreur lors de la suppression de ${dirPath}:`, err);
    }
  }
}

// Tenter de supprimer le répertoire 'data' (qui est peut-être vide)
removeEmptyDirectory('data');
// Tenter de supprimer 'uploads' (qui contient probablement des sous-dossiers -> ENOTEMPTY)
removeEmptyDirectory('uploads');

Limitation : `rmdir` est très limitée car elle ne fonctionne que sur les répertoires vides. Pour supprimer un répertoire et tout son contenu, il fallait historiquement lire récursivement le contenu et supprimer chaque élément individuellement, ce qui est complexe et source d'erreurs. Heureusement, une fonction plus moderne existe maintenant.

Suppression moderne et recursive : `rm`

Introduite dans les versions plus récentes de Node.js (v14.14.0+), la fonction `fs.rm()` (et `fs.promises.rm()` / `fs.rmSync()`) est la méthode moderne et recommandée pour supprimer à la fois des fichiers et des répertoires, y compris de manière récursive.

Signature de la version promesse :

fs.promises.rm(path, [options])
  • path : Le chemin du fichier ou répertoire à supprimer.
  • options (optionnel) : Objet contenant notamment :
    • recursive (booléen) : Si `true`, supprime les répertoires et leur contenu de manière récursive (équivalent de `rm -rf`). A utiliser avec une extrême prudence ! Par défaut `false`.
    • force (booléen) : Si `true`, les exceptions seront ignorées si `path` n'existe pas. Par défaut `false`.
    • maxRetries, retryDelay : Pour gérer les erreurs temporaires.

Exemple de suppression récursive :

const fs = require('fs').promises;

async function cleanupUploads(dirPath) {
  console.log(`Tentative de suppression récursive de ${dirPath}...`);
  try {
    await fs.rm(dirPath, { recursive: true, force: true });
    // force: true -> ne pas échouer si 'dirPath' n'existe pas
    // recursive: true -> supprimer tout le contenu
    console.log(`Répertoire ${dirPath} et son contenu supprimés (ou n'existaient pas).`);
  } catch (err) {
    // Normalement, avec force:true, ENOENT est ignoré.
    // Gérer d'autres erreurs potentielles (permissions EACCES...)
    console.error(`Erreur inattendue lors de la suppression de ${dirPath}:`, err);
  }
}

// Nettoyer le répertoire 'uploads' créé précédemment
cleanupUploads('uploads');

L'utilisation de `fs.rm` avec `recursive: true` simplifie grandement la suppression de structures de répertoires entières par rapport aux anciennes méthodes manuelles ou à `rmdir`.

En conclusion, le module `fs` fournit tous les outils nécessaires pour gérer la structure du système de fichiers. Privilégiez toujours les versions asynchrones (promesses avec `async/await`) et utilisez la fonction moderne `fs.rm` pour les suppressions, en particulier récursives, tout en étant très prudent avec l'option `recursive: true`.