Fi

File em Elixir

2 exercícios

Sobre File

As funções para trabalhar com ficheiros são fornecidas pelo módulo File.

Para ler um ficheiro inteiro, usa File.read/1. Para escrever num ficheiro, usa File.write/2.

O módulo também fornece funções para ficheiros, como copiar, remover, renomear, etc. Os seus nomes são semelhantes aos equivalentes UNIX, por exemplo:

Todas as funções mencionadas do módulo File também têm uma variante com ! que lança um erro em vez de devolver um tuplo de erro (por exemplo, File.read!/1). Usa essa variante se não pretendes tratar erros como ficheiros em falta ou falta de permissões.

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

Ficheiros e processos

Cada vez que escreves num ficheiro com File.write/2, é aberto um descritor de ficheiro e é criado um novo processo Elixir. Por isso, deves evitar escrever num ficheiro num ciclo com File.write/2.

Em vez disso, podes abrir um ficheiro com File.open/2. O segundo argumento de File.open/2 é uma lista de modos, que te permite especificar se queres abrir o ficheiro para leitura ou para escrita.

Os modos mais usados são:

  • :read - abrir para leitura; o ficheiro tem de existir
  • :write - abrir para escrita; o ficheiro será criado se não existir; o conteúdo existente será substituído
  • :append - abrir para escrita; o ficheiro será criado se não existir; o conteúdo existente será preservado

Para uma lista completa de todos os modos, consulta a documentação de File.open/2.

File.open/2 devolve um PID de um processo que trata do ficheiro. Para ler e escrever no ficheiro, usa funções do módulo IO e passa este PID como dispositivo de E/S.

Quando acabares de trabalhar com o ficheiro, fecha-o com File.close/1.

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

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

File.close(file)
# => :ok

Ficheiros em fluxo

Ler um ficheiro com File.read/1 carrega o ficheiro inteiro para a memória de uma só vez. Isto pode ser um problema quando trabalhas com ficheiros muito grandes. Para os tratar de forma eficiente, podes usar File.open/2 e IO.read/2 para ler o ficheiro linha a linha, ou podes processar o ficheiro em fluxo com File.stream/3. O fluxo implementa os protocolos Enumerable e Collectable, o que significa que pode ser usado tanto para leitura como para escrita.

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

Caminhos

Todas as funções que trabalham com ficheiros exigem um caminho de ficheiro. Os caminhos de ficheiro podem ser absolutos ou relativos ao diretório atual. Para manipular caminhos, usa funções do módulo Path. Para compatibilidade entre plataformas, usa Path.join/1 para criar caminhos. Escolherá o separador adequado à plataforma.

Path.expand(Path.join(["~", "documents", "important.txt"]))
"/home/user/documents/important.txt"
Editar via GitHub A ligação abre numa nova janela ou separador

Aprende File

A prática está bloqueada

Desbloqueia mais 1 exercício para praticares File