Arquivos
Ler, escrever e organizar arquivos com Arcane.IO, e compactar com Arcane.Archive.
Texto#
dataforge
adopt Arcane.IO as IO
IO.write(caminho, texto) # cria ou substitui
IO.append(caminho, texto) # acrescenta ao fim
IO.read(caminho) # devolve o conteúdo
cycle linha in IO.read("dados.txt").lines():
processar(linha)Formatos estruturados#
dataforge
IO.write_json(caminho, vault) IO.read_json(caminho)
IO.write_csv(caminho, linhas) IO.read_csv(caminho)Fazem a serialização e a escrita numa chamada só.
Caminhos#
dataforge
IO.join(pasta, "arquivo.txt") # monta com o separador certo
IO.basename(caminho) # "notas.txt"
IO.dirname(caminho) # a pasta
IO.ext(caminho) # ".txt"
IO.abs(caminho) # caminho absolutoDiretórios#
dataforge
IO.mkdir(pasta) # cria, inclusive os níveis intermediários
IO.list_dir(pasta) # os nomes dentro dela
IO.exists(caminho) # arquivo ou pasta
IO.file_exists(caminho) # só arquivo
IO.size(caminho) # bytesCopiar, mover, apagar#
dataforge
IO.copy(origem, destino)
IO.rename(antigo, novo) # também move entre pastas
IO.delete(caminho)Filtrar por extensão#
dataforge
textos := IO.list_dir(pasta) >> sift nome: nome.endswith(".txt")list_dir devolve uma lista comum, então todo o pipeline funciona sobre ela.
Zip e tar#
Arcane.Archive compacta e extrai. É um módulo à parte porque a extração tem uma responsabilidade que a leitura de arquivo não tem: o conteúdo veio de fora.
dataforge
adopt Arcane.Archive as Zip
Zip.compactar("relatorios", "backup.zip") # pasta inteira
Zip.extrair("backup.zip", "destino")
Zip.listar("backup.zip") # sem extrair
Zip.ler_de("backup.zip", "relatorios/jan.csv") # um arquivo só
Zip.conferir("backup.zip") # está íntegro?
Zip.acrescentar("backup.zip", "mar.csv")
Zip.compactar_tar("projeto", "projeto.tar.gz")
Zip.extrair_tar("projeto.tar.gz", "destino")O que a extração recusa#
Extrair um arquivo de origem desconhecida é perigoso, e os dois riscos têm nome próprio justamente por terem sido explorados muitas vezes:
| Ataque | O que faz | A defesa aqui |
|---|---|---|
| Zip Slip | uma entrada chamada ../../.ssh/authorized_keys escreve fora da pasta de destino | o caminho final é resolvido e comparado com o destino; .. e link simbólico já foram desfeitos |
| Zip bomb | 1 KB que descompacta para 10 GB, enchendo o disco | o tamanho declarado é somado antes de extrair |
| Link no tar | uma entrada que é link simbólico e aponta para qualquer lugar do sistema | recusada; e o filter="data" do Python barra permissão estranha e dono de outro usuário |
Para guardar o pacote cifrado, Arcane.Crypto.cifrar_pasta compacta e cifra num passo — ver Criptografia.
Limpeza garantida#
Use defer para garantir a limpeza mesmo se algo falhar no meio:
dataforge
action processar():
IO.write(temp, "dados")
defer:
given IO.exists(temp):
IO.delete(temp)
# ... o defer roda mesmo se isto disparar
yield resultadoDetalhes em Tratamento de erros.
Um relatório de pasta#
dataforge
action formatar_bytes(n) -> String:
given n smaller 1024:
yield $"{n} B"
orif n smaller 1048576:
yield $"{round(n / 1024, 1)} KB"
yield $"{round(n / 1048576, 2)} MB"
cycle nome in IO.list_dir("."):
caminho := IO.join(".", nome)
given IO.file_exists(caminho):
out $"{nome.pad_end(24)}{formatar_bytes(IO.size(caminho)).pad_start(10)}"