Pular para o conteúdo principal

Interagindo com o sistema de arquivos

Criar uma pasta

No Linux

$ mkdir pasta1

No Python

>>> import os
>>> os.mkdir("pasta2")

Acessar uma pasta

No linux

$ cd pasta1

No Python

>>> import os
>>> os.chdir("pasta2")

Exibir a pasta atual

No Linux

$ pwd
/path/pasta1

No Python

>>> import os
>>> os.path.abspath(os.curdir)
/path/pasta2

Criar um arquivo em branco

No linux

$ touch arquivo.txt

No Python

>>> open("arquivo.txt", "w")

Listar arquivos

No linux:

$ ls
arquivo.txt

No Python

>>> import os
>>> os.listdir(".")
['arquivo.txt']

Escrever em um arquivo

No Linux

$ echo "Hello" >> arquivo.txt

nota "w" escreve no modo w substituindo todo o conteúdo do arquivo e "a" escreve no modo a fazendo append no final do arquivo existente.

Ler o conteúdo de um arquivo

No Linux

$ cat arquivo.txt
Hello

No Python

>>> print(open("arquivo.txt", "r").read())
'Hello\n'

Dicas úteis ao trabalhar com arquivos no Python

Context manager

Nós ainda não falamos sobre este tema, mas para trabalhar com arquivos ele é essencial, no exemplo de escrita em arquivos nós tivemos que chamar a função .close() explicitamente.

>>> arquivo =  open("arquivo.txt", "a")
>>> arquivo.write("Hello\n")
>>> arquivo.close()

Como é muito importante manter os descritores de arquivo devidamente encerrados em Python sempre ao abrir um arquivo iremos dar preferência para o uso de um context manager, que é um bloco especial de código que automaticamente executa operações como o .close em arquivos.

A maneira preferida será sempre:

with open("arquivo.txt", "a") as arquivo:
# aqui temos o arquivo aberto para escrever

arquivo.write("Hello")

# aqui o context manager garante o fechamento do arquivo
# sem a necessidade de chamarmos explicitamente o .close()

Criar diretórios não existem em um caminho

>>> os.mkdir("um/outro/maisoutro/)
FileNotFoundError: [Errno 2] No such file or directory: 'um/outro/maisoutro/'

Para o código acima funcionar teríamos que criar primeiro um e depois outro e assim por diante, portanto quando temos múltiplas pastas para criar vamos preferir usar a função makedirs

>>> os.makedirs("um/outro/maisoutro", exist_ok=True)
>>> os.listdir("um")
['outro']
>>> os.listdir("um/outro")
['maisoutro']

Ler múltiplas linhas de um arquivo

Um arquivo de texto pode ter milhares de linhas e ao efetuar a leitura com .read isso pode causar um estouro de memória:

>>> open("arquivo_grande.txt", "r").read()
Error: Not Enough Memory to load 20GB

Neste caso devemos usar o procolo de iteração, os file descriptors são iteráveis, e melhor que isso eles são geradores de dados.

Isso quer dizer que dentro de um loop, a leitura do arquivo linha a linha será mais eficiente:

for linha in open("arquivo_grande.txt", "r"):
print(linha)

Vai imprimir tranquilamente pois mesmo que o arquivo tenha 20GB será carregado para a memória apenas uma linha de cada vez.

Escrever múltiplas linhas em um arquivo

texto = [
"Este é um texto",
"cada item desta lista",
"é uma linha no arquivo",
]

with open("arquivo.txt", "a") as arquivo:
arquivo.writelines("\n".join(texto))

No linux pode ler com:

$ cat arquivo.txt
Este é um texto
cada item desta lista
é uma linha no arquivo

Lendo multiplas linhas de um arquivo

Lembrando que isso só deve ser feito em arquivos de tamanho pequeno.

>>> open("arquivo.txt").readlines()
['Este é um texto\n', 'cada item desta lista\n', 'é uma linha no arquivo']

Trabalhando com caminhos

# Juntando caminhos
>>> import os
>>> os.path.join("pasta2/pasta3/arquivo.txt")
pasta2/pasta3/arquivo.txt

# Obtendo caminho absoluto
>>> os.path.abspath(os.path.join("pasta2/pasta3/arquivo.txt"))
/home/user/pasta2/pasta3/arquivo.txt

# Obtendo o caminho absoluto para o diretorio atual
>>> os.path.abspath(os.curdir)
/tmp/pasta2/foo/

A Pathlib

A pathlib foi adicionada no Python 3 e provê as mesmas funcionalidades do os e open com algumas melhorias de sintaxe.

>>> from pathlib import Path
# Criar pasta
>>> Path("pasta3").mkdir(parents=True, exist_ok=True)
# Criar arquivo na pasta
>>> Path("pasta3/arquivo.txt").touch()
# Escrever no arquivo
>>> Path("pasta3/arquivo.txt").write_text("Bruno")
# Ler o conteúdo do arquivo
>>> Path("pasta3/arquivo.txt").read_text()
'Bruno'

Uma característica interessante do objeto Path é que ele permite ser combinado com outros objetos do mesmo tipo ou str usando /.

>>> caminho = Path("pasta1") / "pasta2" / Path("pasta3")
>>> print(caminho)
pasta1/pasta2/pasta3

Conclusão

A escolha entre utilizar os ou pathlib se dá pelo gosto de quem está programando. As funcionalidades são as mesmas e na maioria dos casos as funções executadas serão as mesmas, cabe a quem estiver programando verificar qual das interfaces está lidando na hora de interagir com os objetos file descriptors.

guia de referencia

Exemplo

#!/usr/bin/env python3
"""Bloco de notas

$ notes.py new "Minha Nota"
tag: tech
text:
Anotacao geral sobre carreira de tecnologia

$ notes.py 1 tech
...
...
"""
__version__ = "0.1.0"

import os
import sys

cmds = ("read", "new")
path = os.curdir
filepath = os.path.join(path, "notes.txt")

arguments = sys.argv[1:]
if not arguments:
print("Invalid usage")
print(f"you must specify subcommand {cmds}")
sys.exit(1)

if arguments[0] not in cmds:
print(f"Invalid command {argument[0]}")

if arguments[0] == "read":
# leitura das notas
for line in open(filepath):
title, tag, text = line.split("\t")
if tag.lower() == arguments[1].lower():
print(f"title: {title}")
print(f"text: {text}")
print("-" * 30)
print()

if arguments[0] == "new":
title = arguments[1]
text = [
f"{title}",
input("tag:").strip(),
input("text:\n").strip(),
]
# \t - tsv
with open(filepath, "a") as file_:
file_.write("\t".join(text) + "\n")