Le funzioni per lavorare con i file sono fornite dal modulo File.
Per leggere un intero file, usa File.read/1. Per scrivere su un file, usa File.write/2.
Il modulo fornisce anche funzioni per copiare, rimuovere, rinominare i file e così via. I loro nomi sono simili a quelli delle equivalenti UNIX, per esempio:
File.cp/3: copia un file.File.rm/1: elimina un file.File.rename/2: rinomina e/o sposta un file.File.mkdir/1: crea una directory.File.cwd/0: ottieni la directory di lavoro corrente.Tutte le funzioni menzionate del modulo File hanno anche una variante con ! che solleva un errore invece di restituire una tupla di errore (ad esempio File.read!/1). Usa quella variante se non hai intenzione di gestire errori come file mancanti o permessi insufficienti.
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
Ogni volta che si scrive su un file con File.write/2, viene aperto un descrittore di file e viene generato un nuovo processo Elixir. Per questo motivo, conviene evitare di scrivere su un file in un ciclo usando File.write/2.
Invece, un file può essere aperto usando File.open/2. Il secondo argomento di File.open/2 è un array di modalità, che ti permette di specificare se vuoi aprire il file in lettura o in scrittura.
Le modalità più usate sono:
:read: apre in lettura, il file deve esistere:write: apre in scrittura, il file viene creato se non esiste, il contenuto esistente viene sovrascritto:append: apre in scrittura, il file viene creato se non esiste, il contenuto esistente viene conservatoPer conoscere tutte le modalità disponibili, consulta la documentazione di File.open/2.
File.open/2 restituisce il PID di un processo che gestisce il file. Per leggere e scrivere sul file, usa le funzioni del modulo IO e passa questo PID come dispositivo IO.
Quando hai finito di lavorare con il file, chiudilo con File.close/1.
file = File.open!("README.txt", [:write])
# => #PID<0.157.0>
IO.puts(file, "# README")
# => :ok
File.close(file)
# => :ok
Leggere un file con File.read/1 carica l'intero file in memoria tutto in una volta. Questo può essere un problema quando si lavora con file davvero grandi. Per gestirli in modo efficiente, puoi usare File.open/2 e IO.read/2 per leggere il file riga per riga, oppure puoi ricorrere allo streaming con File.stream/3. Lo stream implementa sia il protocollo Enumerable sia il Collectable, quindi può essere usato sia per leggere sia per scrivere.
File.stream!("file.txt")
|> Stream.map(&(&1 <> "!"))
|> Stream.into(File.stream!("new_file.txt"))
|> Stream.run()
Tutte le funzioni che lavorano sui file richiedono un percorso di file. I percorsi possono essere assoluti o relativi alla directory corrente. Per manipolare i percorsi, usa le funzioni del modulo Path. Per garantire la compatibilità tra piattaforme, usa Path.join/1 per costruire i percorsi: sceglierà il separatore adatto alla piattaforma.
Path.expand(Path.join(["~", "documents", "important.txt"]))
"/home/user/documents/important.txt"