Sistema de arquivos
Ler, escrever, percorrer e não deixar lixo — Arcane.IO e Arcane.OS na prática.
Dois módulos dividem o trabalho: `Arcane.IO` mexe em arquivos e pastas; `Arcane.OS` responde sobre o ambiente — onde é a casa, qual é o temporário, o que há no PATH.
Ler e escrever#
adopt Arcane.IO as IO
IO.write("notas.txt", "primeira linha\n")
IO.append("notas.txt", "segunda linha\n")
out IO.read("notas.txt").strip().split("\n")
out IO.exists("notas.txt"), IO.size("notas.txt")[primeira linha, segunda linha]
yes 29IO.write sobrescreve; IO.append acrescenta. Não há modo intermediário de propósito: um terceiro verbo com semântica sutil é o tipo de coisa que se erra às três da manhã.
Caminhos: monte, não concatene#
IO.join(pasta, "dados", "brutos.csv") // usa o separador do sistema
IO.basename("/tmp/a/b.txt") // b.txt
IO.dirname("/tmp/a/b.txt") // /tmp/a
IO.ext("/tmp/a/b.txt") // .txt
IO.abs("./relativo") // o caminho absolutoConcatenar com + produz um caminho que funciona no seu computador e falha no Windows — e o teste local nunca pega.
JSON e CSV, sem cerimônia#
adopt Arcane.IO as IO
IO.write_json("config.json", {"porta": 8000, "debug": yes})
out IO.read_json("config.json")["porta"] // 8000
// um cluster de VAULTS: a primeira linha vira o cabeçalho
IO.write_csv("dados.csv", [{"nome": "Ana", "idade": 30},
{"nome": "Bruno", "idade": 25}])
out IO.read("dados.csv").strip()nome,idade
Ana,30
Bruno,25Na leitura, escolha a forma:
linhas := IO.read_csv("dados.csv") // cluster de clusters
linhas := IO.read_csv("dados.csv", yes) // cluster de VAULTS, pelo cabeçalhoPastas#
adopt Arcane.IO as IO
IO.mkdir("saida") // cria, inclusive os pais
out IO.list_dir("saida") // o que há dentro
IO.copy("a.txt", "saida/a.txt")
IO.copy_tree("modelos", "saida/modelos")
IO.rename("saida/a.txt", "saida/b.txt")
IO.delete("saida/b.txt") // um arquivo
IO.remove_tree("saida") // a pasta inteiraTemporário: sempre uma subpasta sua#
adopt Arcane.IO as IO
adopt Arcane.OS as OS
base := $"{OS.temp_dir()}/meu-programa-{randint(100000, 999999)}"
IO.mkdir(base)
defer:
IO.remove_tree(base) // roda na saída da ação, inclusive por erro
IO.write(IO.join(base, "trabalho.txt"), "…")O defer é o que garante a limpeza quando a ação sai por erro — que é justamente quando ninguém lembra de limpar.
O ambiente, com `Arcane.OS`#
| Pergunta | Resposta |
|---|---|
| onde estou? | OS.cwd() |
| onde está o script? | OS.script_dir() |
| qual é a casa do usuário? | OS.home() |
| qual é o temporário? | OS.temp_dir() |
| qual sistema? | OS.is_windows(), OS.is_mac(), OS.is_linux() |
| quantos núcleos? | OS.cpu_count() |
| a variável de ambiente | OS.get_env(nome, padrao), OS.set_env, OS.unset_env |
| este comando existe? | OS.which("git") |
OS.unset_env existe porque a falta dela aparecia como poluição entre execuções: um exercício imprimia 77 variáveis na primeira rodada e 78 na segunda. Ela devolve yes/no em vez de levantar — remover é pedir um estado final, e nesse ponto já não importa se estava lá.
Arquivo grande: não carregue inteiro#
IO.read traz tudo para a memória. Para um arquivo maior que a RAM, processe por partes — ver complexidade de espaço.
// O(n) de espaço: o arquivo inteiro na memória
todas := IO.read("grande.csv").split("\n")
// O(1) de espaço: uma linha por vez
stream action linhas_de(caminho):
cycle linha in IO.read(caminho).split("\n"):
emit linha
out linhas_de("grande.csv").take(3)Erros: o que pode falhar, e como#
| Situação | O que acontece |
|---|---|
| ler arquivo que não existe | erro, com o caminho na mensagem |
| escrever em pasta que não existe | erro — crie com IO.mkdir antes |
| escrever sem permissão | erro do sistema, traduzido |
delete de algo ausente | erro — confira com IO.exists |
| arquivo fora de UTF-8 | erro de leitura, dizendo qual arquivo |
monitor:
config := IO.read_json("config.json")
handle Error as e:
out $"usando o padrao: {e.message}"
config := {"porta": 8000}