01 / 27
Lógica de Programação · Semana 20 · Dia 1 (aulas 1 e 2)

O programa acabou.
E o dado, sumiu.

Tudo o que vocês construíram até aqui — listas, matrizes, funções, validadores — vive só enquanto o programa está rodando. Hoje o dado passa a sobreviver. E aprende a ser lido sem entupir a memória.

ProfessorGuilherme Antunes CursoTécnico em Desenvolvimento de Sistemas ConteúdoArquivos — entrada e saída CódigosSISANO1C1B3S20A1 · A2
02 / 27
Objetivos do dia

Ao final, você será capaz de.

01

Abrir arquivos com open() escolhendo modo e encoding de forma consciente

02

Usar with e explicar por que o close() manual é frágil

03

Escolher entre read(), readlines() e iteração direta pelo tamanho do arquivo

04

Filtrar, contar e transformar linhas durante a leitura, sem carregar o arquivo inteiro

Onde estamos: Semana 18 → documentar, testar, depurar. Semana 19 → recortar e validar texto. Agora → fazer esse texto persistir. É a última peça antes de o programa virar sistema.
03 / 27
Ponto de partida Todo mundo escreve

O celular que nunca descansa

Marina abre vários aplicativos e nunca fecha nenhum — só minimiza. Com o tempo o aparelho esquenta, a bateria acaba em poucas horas e alguns apps travam. Ela reinicia e não entende o motivo.

Um técnico explica: cada app aberto ocupa uma fatia da memória RAM. Quando todos pedem espaço ao mesmo tempo, o sistema fica sobrecarregado.
Em Python é igual. Cada open() sem o fechamento correspondente é um recurso preso na memória — silenciosamente, até o sistema travar ou emitir erro.

Todo mundo escreve (2 min, no caderno): por que fechar um recurso depois do uso é tão importante quanto abri-lo corretamente? E o que pode acontecer quando um programa abre muitos arquivos e nenhum é fechado?

04 / 27
Construindo o conceito

O que é um arquivo para o Python

Não é o conteúdo

É um canal de comunicação entre o programa e o dispositivo de armazenamento — HD, SSD, pendrive, o que for.

Antes de ler ou gravar qualquer coisa, o canal precisa ser aberto. Terminado o trabalho, precisa ser fechado.

O limite que ninguém vê

O sistema operacional mantém uma tabela de arquivos abertos, e cada processo tem um teto. No Linux, o padrão é 1024 descritores por processo.

Um programa que abre sem fechar chega a esse teto e passa a dar erro — mesmo com o código parecendo correto. O erro aparece longe de onde nasceu.
Guardem a palavra "vazamento": recurso que o programa pegou e não devolveu. Vale para arquivo, conexão de banco e socket de rede. A solução é sempre a mesma — e vocês vão ver ela daqui a três slides.
05 / 27
Construindo o conceito

A função open()

open(arquivo, modo, encoding)

# caminho relativo
open("dados.txt", "r", encoding="utf-8")

# caminho absoluto
open("/home/ana/dados.txt", "r", encoding="utf-8")

Os três parâmetros

  • arquivo — o caminho. Relativo parte da pasta onde o programa roda.
  • modo — a intenção da abertura: ler, escrever, acrescentar.
  • encoding — como os bytes viram texto. Em Python 3, sempre "utf-8".
Omitir o encoding é a origem do acento que vira ç. Sem ele, o Python usa o padrão do sistema — que muda entre Windows, Linux e a máquina do colega. O código funciona no seu PC e quebra no do outro.
06 / 27
Referência que vale decorar

Os modos de abertura

ModoSignificadoSe o arquivo não existeSe já existe
"r"Leitura (padrão)FileNotFoundErrorlê normalmente
"w"Escritacriaapaga tudo e recomeça
"a"Acréscimocriaescreve no final, sem apagar
"x"Criação exclusivacriaFileExistsError
"b"Binário — combina: "rb", "wb"para imagem, PDF, áudio: bytes, não texto
O "w" é a linha mais perigosa deste slide. Ele não pergunta nada, não avisa e não tem desfazer. Abriu em "w", o conteúdo anterior deixou de existir. Amanhã vocês vão ver o estrago disso em um relatório de verdade.
07 / 27
O problema

O close() manual parece certo

Em condições normais, funciona

arquivo = open("dados.txt", "r", encoding="utf-8")
conteudo = arquivo.read()
arquivo.close()

Basta algo dar errado no meio

arquivo = open("dados.txt", "r", encoding="utf-8")
conteudo = arquivo.read()

# ValueError se o conteudo nao for numero
resultado = int(conteudo)

arquivo.close()  # esta linha jamais sera alcancada
A exceção sobe e leva o programa com ela. Tudo o que estava depois do erro simplesmente não roda — inclusive o close(). E o pior: no seu teste com arquivo bonitinho, nunca dá erro. O vazamento só aparece em produção.
08 / 27
A solução · context manager

O with é um guarda de portão

with open("dados.txt", "r", encoding="utf-8") as arquivo:
    conteudo = arquivo.read()
    resultado = int(conteudo)

# aqui o arquivo JA FOI FECHADO automaticamente
# mesmo que int(conteudo) tenha levantado excecao

Na entrada

Abre o recurso e entrega para você com o nome depois do as.

No corpo

Você trabalha. Pode dar erro, pode ter return, pode ter break.

Na saída

Fecha o recurso. Sempre. Com erro ou sem erro. Não existe caminho que escape.

A partir de hoje, open() solto é erro de código nesta disciplina. Se você escreveu open sem with, faltou alguma coisa.
09 / 27
Pause e responda Registro

Dois equívocos de uma vez

Um desenvolvedor carregou um arquivo gigante inteiro na memória e não garantiu que ele seria fechado caso o programa travasse. Quais foram os dois erros?

Acount() não funciona com arquivos de texto
BCaminho incorreto — o código geraria FileNotFoundError
CArquivo não fechado e conteúdo inteiro carregado na memória ✓
DModo de abertura incorreto e encoding desnecessário
Os dois erros são independentes — e cada um tem sua cura: with resolve o primeiro, iteração direta resolve o segundo. É exatamente o que vem a seguir.
10 / 27
Construindo o conceito

Três formas de ler

FormaO que devolveMemóriaQuando usar
f.read()uma única string com tudoarquivo inteiroarquivo pequeno que você quer manipular como texto
f.readlines()lista de strings, uma por linhaarquivo inteiropoucas linhas e você precisa de índice ou ordenação
for linha in fuma linha por vezsó um pedaçoo padrão — qualquer arquivo, qualquer tamanho
with open("dados.txt", "r", encoding="utf-8") as f:
    conteudo = f.read()      # tudo em uma string

with open("dados.txt", "r", encoding="utf-8") as f:
    linhas = f.readlines()   # tudo em uma lista
with open("dados.txt", "r", encoding="utf-8") as f:
    for linha in f:
        print(linha.strip())  # uma por vez
Na dúvida, a terceira. Ela nunca é a errada — só às vezes é mais trabalho.
11 / 27
Aula 2 Construindo o conceito

Por que linha a linha funciona

Com read() ou readlines(), o Python precisa carregar o conteúdo inteiro na RAM antes de entregar qualquer dado. Para 10 KB, tanto faz. Para 2 GB, é inviável.

O buffer

Na iteração direta, o Python mantém internamente um buffer — uma pequena área de memória com apenas um trecho do arquivo. A cada volta do laço ele entrega uma linha e descarta o que já passou.

O resultado

Um programa pode processar um arquivo de 10 GB consumindo apenas alguns kilobytes de RAM.
Onde isso aparece de verdade: log de servidor, exportação de banco, arquivo de importação da folha de pagamento. São os arquivos que ninguém consegue abrir no Bloco de Notas — e que um for de três linhas processa sem suar.
12 / 27
Anatomia da iteração direta

Cada linha vem com um \n grudado

with open("dados.txt", "r", encoding="utf-8") as f:
    for linha in f:
        print(linha.strip())
O .strip() é obrigatório antes de qualquer processamento. Ele tira o \n do fim e os espaços das duas pontas.
arquivo:      "Ana\n"
sem strip:    'Ana\n'   len = 4
com strip:    'Ana'     len = 3

comparacao que falha sem strip:
"Ana\n" == "Ana"   →  False
Detalhe que derruba a turma: a última linha do arquivo pode não ter \n. Então o programa funciona para todas as linhas menos uma — e o defeito parece aleatório. Com .strip() em todas, o problema nem existe.
13 / 27
Anatomia da iteração direta

A linha vazia que não é vazia

Uma linha que parece em branco no arquivo é, na verdade, uma string contendo "\n". Depois do .strip() ela vira "" — e string vazia é False em Python.

with open("dados.txt", "r", encoding="utf-8") as f:
    for linha in f:
        linha = linha.strip()
        if not linha:
            continue          # pula a linha vazia e vai para a proxima
        print(linha)
Esse par strip() + if not linha: continue é padrão de mercado. Copiem no caderno: ele vai abrir praticamente toda leitura de arquivo que vocês escreverem daqui para a frente. Linha em branco no fim do arquivo é a regra, não a exceção.
14 / 27
Construindo o conceito

Filtrar e contar sem guardar nada

Contar ocorrências

contador = 0
with open("servidor.log", "r", encoding="utf-8") as f:
    for linha in f:
        if "ERR_500" in linha:
            contador += 1

print(f"Total de erros: {contador}")

Memória usada: um inteiro. Independe do tamanho do log.

Coletar linhas

erros = []
with open("servidor.log", "r", encoding="utf-8") as f:
    for linha in f:
        linha = linha.strip()
        if linha.startswith("ERRO"):
            erros.append(linha)
Cuidado: a lista cresce durante a leitura. Se o arquivo tiver milhões de linhas de erro, você acabou de recriar o problema do read().
Regra prática: se você só precisa contar ou exibir, processe e descarte. Só guarde na lista o que você realmente vai usar depois — e, se possível, guarde o pedaço, não a linha inteira.
15 / 27
Construindo o conceito

Transformar a linha durante a leitura

with open("vendas.csv", "r", encoding="utf-8") as f:
    next(f)                            # pula o cabecalho
    for linha in f:
        campos = linha.strip().split(",")
        produto = campos[0]
        valor = float(campos[1])
        print(f"{produto}: R$ {valor:.2f}")

next(f)

Aplicado a um arquivo em iteração, avança uma linha sem processá-la. É a forma idiomática de pular o cabeçalho de um CSV.

.split(",")

Divide a linha em uma lista de strings usando a vírgula como separador. Simples e suficiente para CSV básico — a Semana 19 já treinou isso.

Note a ordem: .strip() antes do .split(). Se inverter, o último campo de cada linha carrega o \n — e um dia isso quebra uma comparação.
16 / 27
A armadilha do dia

Vírgula não é vírgula-e-espaço

linha = "Notebook,Eletronico,3200.00"

separador certo:
linha.split(",")
→ ['Notebook', 'Eletronico', '3200.00']

separador com espaco:
linha.split(", ")
→ ['Notebook,Eletronico,3200.00']
O split(", ") não achou o separador — porque não existe vírgula seguida de espaço nessa linha. Ele devolve a linha inteira dentro de uma lista de um elemento.
campos[1] → IndexError: list index out of range
Diagnóstico rápido: ao dar IndexError depois de um split, imprima campos antes de usar. O tamanho da lista entrega o problema na hora.
17 / 27
Pause e responda Registro

Por que este código quebra?

with open("vendas.csv", "r", encoding="utf-8") as f:
    next(f)
    for linha in f:
        campos = linha.strip().split(", ")
        print(campos[1])          # IndexError na primeira linha
AO next(f) pulou linhas além do cabeçalho
BFaltou encoding="utf-8" na abertura
CO separador tem um espaço a mais — o split não dividiu nada ✓
Dprint não aceita item de lista
O erro aponta para o print, mas nasceu no split. É a lição de depuração da Semana 18 aplicada aqui: a linha que estoura quase nunca é a linha que errou.
18 / 27
Prática guiada Até 3 alunos · durante a aula

Leitor de relatório de vendas

Uma pequena loja registra as vendas do dia em um arquivo .csv. Cada linha traz o produto, a categoria e o valor. No fim do expediente, o gerente precisa saber três coisas:

01

Quantas vendas foram realizadas

02

Quais produtos são da categoria Eletronico

03

O valor total arrecadado no dia

Vamos construir juntos, passo a passo. Cinco passos, cada um rodando sozinho. Ninguém avança sem ver a saída esperada na própria tela — se a sua não bate, para e chama.
19 / 27
Prática guiada · passo 1 de 5

Criar o arquivo de dados

Antes de ler, precisamos ter o que ler. Digitem e executem:

conteudo = """produto,categoria,valor
Notebook,Eletronico,3200.00
Caderno,Papelaria,15.50
Smartphone,Eletronico,1800.00
Caneta,Papelaria,3.00
Tablet,Eletronico,950.00
Mochila,Acessorio,189.90
Fone de Ouvido,Eletronico,299.00
"""

with open("vendas.csv", "w", encoding="utf-8") as f:
    f.write(conteudo)

print("Arquivo criado com sucesso!")
Reparem no modo "w": se rodarem este bloco duas vezes, o arquivo é reescrito do zero — e nesse caso está tudo bem, porque é isso que queremos. Amanhã veremos quando não está.
20 / 27
Prática guiada · passo 2 de 5

Ler o arquivo e contar as vendas

total_vendas = 0

with open("vendas.csv", "r", encoding="utf-8") as f:
    next(f)                     # pula o cabecalho
    for linha in f:
        linha = linha.strip()
        if not linha:
            continue
        total_vendas += 1

print(f"Total de vendas: {total_vendas}")
Total de vendas: 7
Se der 8: a linha em branco do fim do arquivo foi contada — o if not linha: continue não está lá ou está fora do lugar.
Se der 0: o programa está rodando em outra pasta. O vendas.csv nasce ao lado do arquivo .py que o criou.
21 / 27
Prática guiada · passo 3 de 5

Filtrar por categoria

print("Produtos eletronicos:")

with open("vendas.csv", "r", encoding="utf-8") as f:
    next(f)
    for linha in f:
        linha = linha.strip()
        if not linha:
            continue
        campos = linha.split(",")
        produto = campos[0]
        categoria = campos[1]
        if categoria == "Eletronico":
            print(f"  - {produto}")
Produtos eletronicos:
  - Notebook
  - Smartphone
  - Tablet
  - Fone de Ouvido
split(",") — sem espaço. É a armadilha de dois slides atrás. Com espaço, dá IndexError na primeira linha.
Por que "Eletronico" sem acento? Porque é assim que está no arquivo. Comparação de string é literal — "Eletronico" == "Eletrônico" é False.
22 / 27
Prática guiada · passo 4 de 5

Somar o total arrecadado

total = 0.0

with open("vendas.csv", "r", encoding="utf-8") as f:
    next(f)
    for linha in f:
        linha = linha.strip()
        if not linha:
            continue
        campos = linha.split(",")
        valor = float(campos[2])
        total += valor

print(f"Total arrecadado: R$ {total:.2f}")
Total arrecadado: R$ 6457.40
Tudo que sai de um arquivo é texto. campos[2] é a string "3200.00", não o número. Sem o float(), o += viraria concatenação — ou TypeError.
O :.2f é o mesmo da Semana 19: duas casas decimais na exibição. Sem ele sai 6457.400000000001 — e ninguém aceita isso em relatório.
23 / 27
Prática guiada · passo 5 de 5

Uma leitura só, três respostas

total_vendas = 0
total_valor = 0.0
eletronicos = []

with open("vendas.csv", "r", encoding="utf-8") as f:
    next(f)
    for linha in f:
        linha = linha.strip()
        if not linha:
            continue
        campos = linha.split(",")
        produto, categoria = campos[0], campos[1]
        valor = float(campos[2])

        total_vendas += 1
        total_valor += valor
        if categoria == "Eletronico":
            eletronicos.append(produto)
print(f"Total de vendas: {total_vendas}")
print(f"Total arrecadado: R$ {total_valor:.2f}")
print(f"Eletronicos: {', '.join(eletronicos)}")
Total de vendas: 7
Total arrecadado: R$ 6457.40
Eletronicos: Notebook, Smartphone, Tablet, Fone de Ouvido
Três perguntas, um for. Abrir o arquivo três vezes funcionava — mas custa três leituras de disco. Com 7 linhas ninguém percebe; com 7 milhões, é a diferença entre 2 segundos e 6.
24 / 27
Para quem terminar antes

Suba um degrau

1

Total por categoria. Em vez de somar tudo junto, some separado por categoria — e imprima cada uma com o valor. Dica: dicionário, ou uma lista de categorias já vistas.

2

Venda mais cara do dia. Guarde produto e valor do maior. Sem max() pronto: com if, como se fazia na Semana 15.

3

Ticket médio. Total dividido pelo número de vendas, com duas casas. Cuidado com divisão por zero se o arquivo vier vazio.

4

Transforme em função. ler_vendas(caminho) devolve os três resultados — com docstring e um assert, como na Semana 18. Nenhum print dentro da função.

O item 4 é o que amarra o bimestre. Documentar, testar, validar e agora persistir — tudo na mesma função de dez linhas.
25 / 27
Circule cobrando isto

Os sete erros de hoje

SintomaCausa provável
FileNotFoundErroro programa roda em outra pasta, ou o nome tem erro de digitação
IndexError após splitseparador errado — ", " em vez de ","
ValueError no floata linha em branco do fim passou pelo filtro
Acento virou "ç"faltou encoding="utf-8"
Comparação sempre Falsefaltou .strip() — a string ainda tem \n
Contagem com 1 a maiso cabeçalho foi contado — faltou next(f)
Arquivo vazio depois de rodarabriu em "w" quando queria ler
26 / 27
Então ficamos assim

O que nós aprendemos hoje

  • Arquivo é recurso do sistema operacional — tem limite, e precisa ser devolvido depois do uso.
  • O close() manual é frágil: uma exceção no meio do caminho impede a execução dele e causa vazamento.
  • O with open() é o padrão correto — fecha o arquivo automaticamente, com erro ou sem erro.
  • A leitura linha a linha usa buffer e permite processar arquivos de qualquer tamanho com pouca memória.
  • Filtrar, contar e transformar durante a leitura evita guardar o arquivo inteiro — e strip() vem sempre antes de split().
Próxima aula

Escrita de relatórios e integração com CSV. Hoje vocês só leram. Amanhã vocês gravam — e vão descobrir, na prática, a diferença entre "w" e "a" pelo caminho mais doloroso: apagando um relatório.

27 / 27
Referências

De onde veio cada coisa

SEDUC-SP. Educação Profissional Paulista — Técnico em Desenvolvimento de Sistemas. Lógica de Programação — Arquivos: entrada e saída (Semana 20, aulas 1 e 2). Códigos: SISANO1C1B3S20A1 e A2.

LUTZ, M. Aprendendo Python. Porto Alegre: Bookman, 2013.

MATTHES, E. Curso intensivo de Python: uma introdução prática e baseada em projetos à programação. São Paulo: Novatec, 2016.

RAMALHO, L. Python fluente: programação clara, concisa e eficaz. São Paulo: Novatec, 2015.

PYTHON SOFTWARE FOUNDATION. Reading and Writing Files e csv — CSV File Reading and Writing. Documentação oficial.

REFATORANDO. Curso de Python para iniciantes #12 — Manipulando Arquivos. YouTube.

Aula compilada (dobradinha) · adaptação para apresentação HTML por Guilherme Antunes