Fi

File en Elixir

2 exercices

À propos de File

Les fonctions permettant de manipuler des fichiers sont fournies par le module File.

Pour lire un fichier entier, utilise File.read/1. Pour écrire dans un fichier, utilise File.write/2.

Le module fournit aussi des fonctions de manipulation de fichiers pour copier, supprimer, renommer, etc. Leurs noms sont semblables à leurs équivalents UNIX, par exemple :

Toutes les fonctions mentionnées du module File ont aussi une variante avec ! qui lève une erreur au lieu de renvoyer un tuple d'erreur (par exemple File.read!/1). Utilise cette variante si tu ne comptes pas gérer des erreurs comme un fichier manquant ou un manque de permissions.

File.read("does_not_exist")
# => {:error, :enoent}

File.read!("does_not_exist")
# => ** (File.Error) could not read file "does_not_exist": no such file or directory
#        (elixir 1.10.4) lib/file.ex:353: File.read!/1

Fichiers et processus

Chaque fois qu'on écrit dans un fichier avec File.write/2, un descripteur de fichier est ouvert et un nouveau processus Elixir est lancé. Pour cette raison, il faut éviter d'écrire dans un fichier en boucle avec File.write/2.

À la place, on peut ouvrir un fichier avec File.open/2. Le deuxième argument de File.open/2 est une liste de modes, qui permet de préciser si l'on veut ouvrir le fichier en lecture ou en écriture.

Les modes les plus courants sont :

  • :read - ouvrir en lecture, le fichier doit exister
  • :write - ouvrir en écriture, le fichier sera créé s'il n'existe pas, le contenu existant sera écrasé
  • :append - ouvrir en écriture, le fichier sera créé s'il n'existe pas, le contenu existant sera conservé

Pour une liste complète de tous les modes, consulte la documentation de File.open/2.

File.open/2 renvoie le PID d'un processus qui gère le fichier. Pour lire et écrire dans le fichier, utilise les fonctions du module IO et passe ce PID comme périphérique d'entrée-sortie.

Quand tu as fini de travailler avec le fichier, ferme-le avec File.close/1.

file = File.open!("README.txt", [:write])
# => #PID<0.157.0>

IO.puts(file, "# README")
# => :ok

File.close(file)
# => :ok

Lire des fichiers en flux

Lire un fichier avec File.read/1 charge tout le fichier en mémoire d'un seul coup. Cela peut poser problème avec des fichiers vraiment volumineux. Pour les traiter efficacement, tu peux utiliser File.open/2 et IO.read/2 pour lire le fichier ligne par ligne, ou bien lire le fichier en flux avec File.stream/3. Le flux implémente à la fois les protocoles Enumerable et Collectable, ce qui signifie qu'il peut servir aussi bien à la lecture qu'à l'écriture.

File.stream!("file.txt")
|> Stream.map(&(&1 <> "!"))
|> Stream.into(File.stream!("new_file.txt"))
|> Stream.run()

Chemins

Toutes les fonctions qui manipulent des fichiers ont besoin d'un chemin de fichier. Les chemins de fichiers peuvent être absolus ou relatifs au répertoire courant. Pour manipuler les chemins, utilise les fonctions du module Path. Pour assurer la compatibilité entre plateformes, utilise Path.join/1 pour construire des chemins. Il choisira le séparateur adapté à la plateforme.

Path.expand(Path.join(["~", "documents", "important.txt"]))
"/home/user/documents/important.txt"
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet

Apprends File

L'entraînement est verrouillé

Déverrouille 1 exercice de plus pour t'entraîner sur File