Introdução à Manipulação de Arquivos
A manipulação de arquivos é uma tarefa fundamental em programação, permitindo que seus scripts leiam dados de arquivos existentes e escrevam resultados em novos arquivos. Em automação de redes, isso é crucial para diversas tarefas, como:
- Ler listas de dispositivos de um arquivo de inventário.
- Carregar templates de configuração.
- Salvar saídas de comandos de dispositivos.
- Gerar relatórios de status ou configuração.
- Processar arquivos de log.
- Trabalhar com dados estruturados em formatos como CSV ou JSON.
Neste módulo, aprenderemos como abrir, ler, escrever e fechar arquivos em Python. Veremos diferentes modos de abertura de arquivos e como usar o gerenciador de contexto with para garantir que os arquivos sejam fechados corretamente. Também abordaremos como trabalhar com formatos de arquivo comuns como CSV e JSON.
Importância para Profissionais de Redes:
A capacidade de ler e escrever arquivos permite que seus scripts de automação interajam com o mundo exterior. Você pode carregar listas de IPs de um arquivo de texto, ler configurações de um arquivo CSV, salvar o output de um `show run` em um arquivo de log, ou gerar um relatório de inventário em formato JSON. Isso torna seus scripts mais flexíveis e integráveis com outras ferramentas e processos.
Abrir e Fechar Arquivos
O primeiro passo para trabalhar com um arquivo é abri-lo. Python fornece a função integrada open() para isso. Após terminar de usar o arquivo, é essencial fechá-lo usando o método close() para liberar os recursos do sistema.
A Função open()
A sintaxe básica da função open() é:
arquivo = open(caminho_do_arquivo, modo, encoding=None)
caminho_do_arquivo: Uma string contendo o nome e, opcionalmente, o caminho para o arquivo.modo: Uma string que especifica como o arquivo será aberto (leitura, escrita, etc.). Este é um parâmetro crucial.encoding: (Opcional, mas recomendado) Especifica a codificação de caracteres a ser usada (ex: “utf-8”, “latin-1”). Usar a codificação correta é vital para evitar erros ao ler ou escrever caracteres especiais. “utf-8” é uma escolha comum e versátil.
Modos de Abertura de Arquivo
Os modos mais comuns são:
'r': Leitura (padrão). Gera um erro se o arquivo não existir.'w': Escrita. Cria um novo arquivo se ele não existir. Sobrescreve o conteúdo se o arquivo já existir.'a': Anexar (append). Escreve no final do arquivo se ele existir. Cria um novo arquivo se ele não existir.'x': Criação exclusiva. Cria um novo arquivo, mas gera um erro se o arquivo já existir.'b': Modo binário (usado para arquivos não-texto, como imagens ou executáveis). Pode ser combinado com outros modos (ex:'rb','wb').'t': Modo texto (padrão). Pode ser combinado com outros modos (ex:'rt','wt').'+': Atualização (leitura e escrita). Pode ser combinado com outros modos (ex:'r+','w+','a+').
Exemplo: Abrindo e Fechando
# Abrindo um arquivo para leitura
try:
# Tenta abrir um arquivo chamado "config.txt" para leitura
# Usando encoding="utf-8" para compatibilidade
arquivo_leitura = open("config.txt", "r", encoding="utf-8")
print("Arquivo config.txt aberto para leitura.")
# ... (operações de leitura aqui) ...
# Fechando o arquivo explicitamente
arquivo_leitura.close()
print("Arquivo config.txt fechado.")
except FileNotFoundError:
print("Erro: O arquivo config.txt não foi encontrado.")
except Exception as e:
print(f"Ocorreu um erro inesperado: {e}")
# Abrindo um arquivo para escrita (sobrescreve se existir)
try:
arquivo_escrita = open("output.log", "w", encoding="utf-8")
print("\nArquivo output.log aberto para escrita.")
# ... (operações de escrita aqui) ...
arquivo_escrita.close()
print("Arquivo output.log fechado.")
except Exception as e:
print(f"Ocorreu um erro ao abrir/escrever no arquivo: {e}")
Importância de Fechar Arquivos:
É crucial fechar os arquivos após o uso. Não fechar arquivos pode levar a problemas como perda de dados (dados podem não ser escritos completamente no disco até que o arquivo seja fechado), consumo excessivo de recursos do sistema (cada arquivo aberto consome um descritor de arquivo) e bloqueio de arquivos para outros processos. Veremos uma maneira mais segura e automática de lidar com isso usando o gerenciador de contexto with.
Ler Arquivos
Depois de abrir um arquivo no modo de leitura ('r' ou 'rt'), você pode usar vários métodos para ler seu conteúdo.
Método read()
O método read(tamanho) lê uma quantidade especificada de bytes (ou caracteres, no modo texto) do arquivo. Se o tamanho não for especificado ou for negativo, ele lê o arquivo inteiro.
# Criando um arquivo de exemplo
with open("ips.txt", "w", encoding="utf-8") as f:
f.write("192.168.1.1\n")
f.write("10.0.0.1\n")
f.write("172.16.0.1\n")
# Lendo o arquivo inteiro
try:
arquivo = open("ips.txt", "r", encoding="utf-8")
conteudo_completo = arquivo.read()
print("Conteúdo completo do arquivo:")
print(conteudo_completo)
arquivo.close()
except FileNotFoundError:
print("Erro: Arquivo ips.txt não encontrado.")
# Lendo uma quantidade específica de caracteres
try:
arquivo = open("ips.txt", "r", encoding="utf-8")
primeiros_10_chars = arquivo.read(10)
print("\nPrimeiros 10 caracteres:")
print(primeiros_10_chars)
arquivo.close()
except FileNotFoundError:
print("Erro: Arquivo ips.txt não encontrado.")
Método readline()
O método readline() lê uma única linha do arquivo, incluindo o caractere de nova linha (\n) no final. Retorna uma string vazia quando o final do arquivo é atingido.
# Lendo linha por linha
try:
arquivo = open("ips.txt", "r", encoding="utf-8")
print("\nLendo linha por linha:")
linha1 = arquivo.readline()
print(f"Linha 1: {linha1.strip()}") # strip() remove espaços em branco e \n
linha2 = arquivo.readline()
print(f"Linha 2: {linha2.strip()}")
linha3 = arquivo.readline()
print(f"Linha 3: {linha3.strip()}")
linha4 = arquivo.readline() # Final do arquivo
print(f"Linha 4 (vazia?): {linha4 == \"\"}")
arquivo.close()
except FileNotFoundError:
print("Erro: Arquivo ips.txt não encontrado.")
Método readlines()
O método readlines() lê todas as linhas restantes do arquivo e as retorna como uma lista de strings, onde cada string representa uma linha e inclui o caractere de nova linha.
# Lendo todas as linhas para uma lista
try:
arquivo = open("ips.txt", "r", encoding="utf-8")
todas_as_linhas = arquivo.readlines()
print("\nTodas as linhas (como lista):")
print(todas_as_linhas)
# Processando a lista de linhas
print("IPs processados:")
for linha in todas_as_linhas:
print(f" - {linha.strip()}")
arquivo.close()
except FileNotFoundError:
print("Erro: Arquivo ips.txt não encontrado.")
Cuidado com readlines() e read():
Os métodos read() (sem argumento) e readlines() carregam todo o conteúdo do arquivo na memória. Isso pode ser problemático para arquivos muito grandes. Para arquivos grandes, é mais eficiente ler linha por linha usando um laço for.
Iterando sobre o Arquivo
A maneira mais idiomática e eficiente em termos de memória para ler um arquivo linha por linha em Python é iterar diretamente sobre o objeto arquivo usando um laço for:
# Iterando sobre o arquivo (método preferido para ler linha por linha)
try:
arquivo = open("ips.txt", "r", encoding="utf-8")
print("\nIterando sobre o arquivo:")
for linha in arquivo:
print(f" Processando: {linha.strip()}")
arquivo.close()
except FileNotFoundError:
print("Erro: Arquivo ips.txt não encontrado.")
Aplicação em Redes: Lendo Lista de Dispositivos
Vamos ler uma lista de IPs de dispositivos de um arquivo:
# Criando um arquivo de inventário simples
inventory_content = """
# Arquivo de inventário de dispositivos
# Formato: hostname,ip_address
Router1,192.168.1.1
Switch1,192.168.1.2
Firewall,192.168.1.254
#Router2,10.0.0.1 # Dispositivo comentado
AccessPoint,192.168.1.100
"""
with open("inventory.txt", "w", encoding="utf-8") as f:
f.write(inventory_content)
def load_devices_from_file(filename):
"""Lê dispositivos de um arquivo de inventário.
Ignora linhas vazias e linhas que começam com #.
"""
devices = []
try:
file = open(filename, "r", encoding="utf-8")
print(f"Lendo dispositivos de ", filename, "...")
for line_num, line in enumerate(file, 1):
line = line.strip() # Remove espaços em branco e \n
# Ignora linhas vazias ou comentários
if not line or line.startswith("#"):
continue
# Divide a linha em hostname e IP
parts = line.split(",")
if len(parts) == 2:
hostname = parts[0].strip()
ip_address = parts[1].strip()
devices.append({"hostname": hostname, "ip": ip_address})
print(f" Linha {line_num}: Adicionado {hostname} ({ip_address})")
else:
print(f" Aviso: Linha {line_num} ignorada (formato inválido): {line}")
file.close()
except FileNotFoundError:
print(f"Erro: Arquivo ", filename, " não encontrado.")
except Exception as e:
print(f"Erro ao ler o arquivo: {e}")
if "file" in locals() and not file.closed:
file.close()
return devices
# Carregando os dispositivos
active_devices = load_devices_from_file("inventory.txt")
# Exibindo os dispositivos carregados
print("\nDispositivos carregados:")
if active_devices:
for device in active_devices:
print(f"- Hostname: {device["hostname"]}, IP: {device["ip"]}")
else:
print("Nenhum dispositivo carregado.")
Este exemplo mostra como ler um arquivo linha por linha, processar cada linha (ignorando comentários e linhas vazias), extrair informações e armazená-las em uma estrutura de dados (lista de dicionários).
Escrever em Arquivos
Para escrever em arquivos, você precisa abri-los nos modos 'w' (escrita, sobrescreve), 'a' (anexar) ou 'x' (criação exclusiva).
Método write()
O método write(string) escreve a string fornecida no arquivo. Ele não adiciona automaticamente um caractere de nova linha (\n); você precisa incluí-lo explicitamente se quiser que cada escrita comece em uma nova linha.
# Escrevendo em um novo arquivo (ou sobrescrevendo)
try:
arquivo = open("config_gerada.txt", "w", encoding="utf-8")
print("Abrindo config_gerada.txt para escrita...")
arquivo.write("hostname Router-Gerado\n")
arquivo.write("!\n")
arquivo.write("interface Loopback0\n")
arquivo.write(" ip address 1.1.1.1 255.255.255.255\n")
arquivo.write("!\n")
print("Configuração escrita no arquivo.")
arquivo.close()
except Exception as e:
print(f"Erro ao escrever no arquivo: {e}")
# Anexando a um arquivo existente
try:
arquivo = open("config_gerada.txt", "a", encoding="utf-8")
print("\nAbrindo config_gerada.txt para anexar...")
arquivo.write("interface GigabitEthernet0/0\n")
arquivo.write(" description Link WAN\n")
arquivo.write(" ip address 10.0.0.1 255.255.255.252\n")
arquivo.write("!\n")
print("Configuração adicional anexada.")
arquivo.close()
except Exception as e:
print(f"Erro ao anexar ao arquivo: {e}")
Método writelines()
O método writelines(lista_de_strings) escreve os itens de uma sequência (como uma lista) no arquivo. Assim como write(), ele não adiciona novas linhas automaticamente; as strings na lista devem conter os caracteres \n se necessário.
# Lista de comandos de configuração
comandos_acl = [
"ip access-list extended ACL_WEB\n",
" permit tcp any any eq 80\n",
" permit tcp any any eq 443\n",
" deny ip any any log\n",
"!\n"
]
# Escrevendo uma lista de linhas
try:
arquivo = open("config_gerada.txt", "a", encoding="utf-8") # Anexando
print("\nAnexando ACL ao arquivo...")
arquivo.writelines(comandos_acl)
print("ACL anexada com sucesso.")
arquivo.close()
except Exception as e:
print(f"Erro ao escrever lista no arquivo: {e}")
Aplicação em Redes: Salvando Saída de Comando
Vamos simular a coleta da saída de um comando e salvá-la em um arquivo:
import datetime
def save_command_output(device_name, command, output):
"""Salva a saída de um comando em um arquivo de log.
O nome do arquivo inclui o nome do dispositivo e um timestamp.
"""
now = datetime.datetime.now()
timestamp = now.strftime("%Y%m%d_%H%M%S")
filename = f"{device_name}_{command.replace(" ", "_")}_{timestamp}.log"
try:
file = open(filename, "w", encoding="utf-8")
print(f"Salvando saída em ", filename, "...")
# Escrevendo cabeçalho
file.write(f"# Dispositivo: {device_name}\n")
file.write(f"# Comando: {command}\n")
file.write(f"# Data/Hora: {now.strftime("%Y-%m-%d %H:%M:%S")}\n")
file.write("-" * 50 + "\n\n")
# Escrevendo a saída do comando
file.write(output)
file.close()
print("Saída salva com sucesso.")
return filename
except Exception as e:
print(f"Erro ao salvar a saída: {e}")
if "file" in locals() and not file.closed:
file.close()
return None
# Saída simulada do comando "show version"
show_version_output = """
Cisco IOS Software, C880 Software (C880DATA-UNIVERSALK9-M), Version 15.0(1)M4
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2010 by Cisco Systems, Inc.
Compiled Fri 29-Oct-10 00:02 by prod_rel_team
ROM: System Bootstrap, Version 12.4(22r)YB5, RELEASE SOFTWARE (fc1)
Router uptime is 1 week, 2 days, 3 hours, 4 minutes
System returned to ROM by power-on
System image file is "flash:c880data-universalk9-mz.150-1.M4.bin"
...
(restante da saída)
..."""
# Salvando a saída
saved_file = save_command_output("Router1", "show version", show_version_output)
if saved_file:
print(f"Verifique o arquivo: {saved_file}")
Este exemplo demonstra como criar um nome de arquivo dinâmico, abrir o arquivo para escrita, adicionar um cabeçalho informativo e, em seguida, escrever a saída do comando. Isso é útil para manter registros históricos das configurações e estados dos dispositivos.
Gerenciador de Contexto (with)
Como mencionado anteriormente, é crucial fechar os arquivos após o uso. No entanto, esquecer de chamar close() ou encontrar um erro antes que close() seja chamado pode deixar arquivos abertos.
Python oferece uma maneira mais segura e conveniente de lidar com arquivos usando a instrução with, conhecida como gerenciador de contexto. Quando você usa with para abrir um arquivo, Python garante que o arquivo seja fechado automaticamente no final do bloco with, mesmo que ocorram erros.
Sintaxe do with
with open(caminho_do_arquivo, modo, encoding="utf-8") as nome_variavel:
# Bloco de código para trabalhar com o arquivo
# Use nome_variavel para acessar o objeto arquivo
# Ex: conteudo = nome_variavel.read()
# Ex: nome_variavel.write("dados")
pass
# Neste ponto, fora do bloco with, o arquivo já está fechado automaticamente.
Exemplo: Lendo com with
# Lendo um arquivo usando with (método recomendado)
def read_ips_with_context(filename):
ips = []
try:
with open(filename, "r", encoding="utf-8") as file:
print(f"Arquivo {filename} aberto com with.")
for line in file:
ips.append(line.strip())
# O arquivo é fechado automaticamente aqui
print(f"Arquivo {filename} fechado automaticamente.")
except FileNotFoundError:
print(f"Erro: Arquivo {filename} não encontrado.")
except Exception as e:
print(f"Erro ao ler o arquivo: {e}")
return ips
# Usando a função
ips_lidos = read_ips_with_context("ips.txt")
print("\nIPs lidos com with:")
print(ips_lidos)
Exemplo: Escrevendo com with
# Escrevendo em um arquivo usando with
def write_config_with_context(filename, config_lines):
try:
with open(filename, "w", encoding="utf-8") as file:
print(f"\nArquivo {filename} aberto para escrita com with.")
for line in config_lines:
file.write(line + "\n") # Adiciona nova linha
# O arquivo é fechado automaticamente aqui
print(f"Arquivo {filename} fechado automaticamente.")
print("Configuração salva com sucesso.")
return True
except Exception as e:
print(f"Erro ao escrever no arquivo: {e}")
return False
# Configuração a ser salva
config_para_salvar = [
"hostname Switch-Core",
"!",
"vlan 100",
" name Servers",
"!",
"interface Vlan100",
" ip address 10.1.100.1 255.255.255.0"
]
# Salvando a configuração
write_config_with_context("switch_core_config.txt", config_para_salvar)
Sempre Use with:
É fortemente recomendado usar a instrução with sempre que trabalhar com arquivos em Python. Ela torna o código mais limpo, mais seguro e menos propenso a erros relacionados a arquivos não fechados.
Aplicação em Redes: Processando Arquivo de Log
Vamos usar with para ler um arquivo de log e extrair mensagens de erro:
# Criando um arquivo de log de exemplo
log_content = """
May 21 10:00:01 Router1 %SYS-5-CONFIG_I: Configured from console by admin
May 21 10:05:15 Router1 %LINK-3-UPDOWN: Interface GigabitEthernet0/1, changed state to down
May 21 10:05:18 Router1 %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet0/1, changed state to down
May 21 10:10:22 Router1 %SYS-3-CPUHOG: Task ran for 2132 msec (21/10), process = ARP Input
May 21 10:15:45 Router1 %LINK-3-UPDOWN: Interface GigabitEthernet0/1, changed state to up
May 21 10:15:47 Router1 %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet0/1, changed state to up
May 21 10:20:05 Router1 %SYS-2-MALLOCFAIL: Memory allocation of 1024 bytes failed
"""
with open("router.log", "w", encoding="utf-8") as f:
f.write(log_content)
def extract_error_messages(log_filename):
"""Lê um arquivo de log e extrai mensagens com severidade <= 3."""
error_messages = []
try:
with open(log_filename, "r", encoding="utf-8") as log_file:
print(f"\nAnalisando {log_filename}...")
for line in log_file:
# Tentando extrair a severidade (ex: %LINK-3-UPDOWN)
severity_match = re.search(r"%\w+-(\d)-\w+:", line)
if severity_match:
severity = int(severity_match.group(1))
if severity <= 3:
error_messages.append(line.strip())
print(f" Erro encontrado (Severidade {severity}): {line.strip()}")
print("Análise concluída.")
except FileNotFoundError:
print(f"Erro: Arquivo {log_filename} não encontrado.")
except Exception as e:
print(f"Erro ao processar o log: {e}")
return error_messages
# Extraindo mensagens de erro
errors = extract_error_messages("router.log")
# Exibindo os erros encontrados
print("\nMensagens de erro extraídas:")
if errors:
for error in errors:
print(f"- {error}")
else:
print("Nenhuma mensagem de erro (severidade <= 3) encontrada.")
Este exemplo demonstra a segurança e a clareza do uso de with para garantir que o arquivo de log seja fechado corretamente, mesmo durante o processamento linha por linha.
Trabalhando com Formatos Comuns (CSV, JSON)
Em automação de redes, é comum trabalhar com dados estruturados em formatos como CSV (Comma-Separated Values) e JSON (JavaScript Object Notation). Python possui módulos integrados para facilitar a leitura e escrita desses formatos.
Trabalhando com CSV
O módulo csv permite ler e escrever arquivos CSV.
import csv
# Dados de exemplo para escrever em CSV
devices_data = [
["hostname", "ip_address", "model", "location"],
["Router1", "192.168.1.1", "Cisco 2901", "Data Center"],
["Switch1", "192.168.1.2", "Cisco 3750", "Data Center"],
["Firewall1", "192.168.1.254", "ASA 5506", "Edge"]
]
# Escrevendo em um arquivo CSV
csv_filename = "inventory.csv"
try:
with open(csv_filename, "w", newline="", encoding="utf-8") as csvfile:
# newline="" é importante para evitar linhas em branco extras
writer = csv.writer(csvfile)
print(f"Escrevendo dados em {csv_filename}...")
writer.writerows(devices_data)
print("Arquivo CSV escrito com sucesso.")
except Exception as e:
print(f"Erro ao escrever CSV: {e}")
# Lendo de um arquivo CSV
read_devices = []
try:
with open(csv_filename, "r", newline="", encoding="utf-8") as csvfile:
reader = csv.reader(csvfile)
print(f"\nLendo dados de {csv_filename}...")
header = next(reader) # Lê a linha de cabeçalho
print(f"Cabeçalho: {header}")
for row in reader:
# Cria um dicionário para cada linha
device_dict = dict(zip(header, row))
read_devices.append(device_dict)
print(f" Lido: {row}")
print("Arquivo CSV lido com sucesso.")
except FileNotFoundError:
print(f"Erro: Arquivo {csv_filename} não encontrado.")
except Exception as e:
print(f"Erro ao ler CSV: {e}")
# Exibindo os dados lidos
print("\nDados lidos do CSV (como dicionários):")
for device in read_devices:
print(device)
Trabalhando com JSON
O módulo json permite codificar estruturas de dados Python em strings JSON e decodificar strings JSON de volta para estruturas de dados Python.
import json
# Dados de exemplo (lista de dicionários)
inventory_data = [
{"hostname": "R1", "ip": "192.168.1.1", "type": "router"},
{"hostname": "S1", "ip": "192.168.1.2", "type": "switch"},
{"hostname": "AP1", "ip": "192.168.1.3", "type": "access_point"}
]
# Escrevendo em um arquivo JSON
json_filename = "inventory.json"
try:
with open(json_filename, "w", encoding="utf-8") as jsonfile:
print(f"\nEscrevendo dados em {json_filename}...")
# json.dump escreve o objeto Python no arquivo como JSON
# indent=4 formata o JSON para melhor legibilidade
json.dump(inventory_data, jsonfile, indent=4)
print("Arquivo JSON escrito com sucesso.")
except Exception as e:
print(f"Erro ao escrever JSON: {e}")
# Lendo de um arquivo JSON
loaded_inventory = []
try:
with open(json_filename, "r", encoding="utf-8") as jsonfile:
print(f"\nLendo dados de {json_filename}...")
# json.load lê o JSON do arquivo e o converte para um objeto Python
loaded_inventory = json.load(jsonfile)
print("Arquivo JSON lido com sucesso.")
except FileNotFoundError:
print(f"Erro: Arquivo {json_filename} não encontrado.")
except json.JSONDecodeError as e:
print(f"Erro ao decodificar JSON: {e}")
except Exception as e:
print(f"Erro ao ler JSON: {e}")
# Exibindo os dados carregados
print("\nDados carregados do JSON:")
if isinstance(loaded_inventory, list):
for item in loaded_inventory:
print(item)
else:
print(loaded_inventory)
JSON vs CSV:
CSV é simples e bom para dados tabulares (planilhas). É fácil de ler e escrever por humanos e softwares de planilha. No entanto, não suporta nativamente estruturas de dados aninhadas ou tipos de dados complexos.
JSON é mais flexível e pode representar estruturas de dados complexas, incluindo listas e dicionários aninhados. É amplamente utilizado em APIs web e arquivos de configuração. É menos legível para humanos que CSV simples, mas mais poderoso para representar dados estruturados.
A escolha entre CSV e JSON depende dos requisitos específicos da sua aplicação e dos sistemas com os quais você precisa interagir.
Exercícios Práticos
Exercício 1: Contador de Linhas de Configuração
Crie um script Python que leia um arquivo de configuração Cisco e conte o número total de linhas, o número de linhas de comentário (começando com !) e o número de linhas de configuração não vazias.
Solução do Exercício 1:
#!/usr/bin/env python3
# Contador de Linhas de Configuração
import re
def count_config_lines(filename):
"""Conta diferentes tipos de linhas em um arquivo de configuração."""
total_lines = 0
comment_lines = 0
config_lines = 0
empty_lines = 0
try:
with open(filename, "r", encoding="utf-8") as file:
for line in file:
total_lines += 1
line_stripped = line.strip()
if not line_stripped:
empty_lines += 1
elif line_stripped.startswith("!"):
comment_lines += 1
else:
config_lines += 1
except FileNotFoundError:
print(f"Erro: Arquivo ", filename, " não encontrado.")
return None
except Exception as e:
print(f"Erro ao ler o arquivo: {e}")
return None
return {
"total": total_lines,
"comments": comment_lines,
"config": config_lines,
"empty": empty_lines
}
# Criando um arquivo de configuração de exemplo
config_content = """
! Arquivo de configuração exemplo
version 15.4
!
hostname MyRouter
!
interface GigabitEthernet0/0
description WAN Link
ip address 10.0.0.1 255.255.255.252
!
! Seção de ACLs
ip access-list standard MY_ACL
permit 192.168.1.0 0.0.0.255
! Fim da configuração
"""
config_filename = "sample_config.txt"
with open(config_filename, "w", encoding="utf-8") as f:
f.write(config_content)
# Contando as linhas
counts = count_config_lines(config_filename)
# Exibindo os resultados
if counts:
print(f"\nAnálise do arquivo: {config_filename}")
print(f"- Total de linhas: {counts["total"]}")
print(f"- Linhas de comentário (!): {counts["comments"]}")
print(f"- Linhas de configuração: {counts["config"]}")
print(f"- Linhas vazias: {counts["empty"]}")
Exercício 2: Gerador de Inventário CSV
Crie um script que leia uma lista de dicionários representando dispositivos de rede e gere um arquivo CSV com essas informações.
Solução do Exercício 2:
#!/usr/bin/env python3
# Gerador de Inventário CSV
import csv
def generate_inventory_csv(devices, filename):
"""Gera um arquivo CSV a partir de uma lista de dicionários de dispositivos."""
if not devices:
print("Lista de dispositivos vazia. Nenhum arquivo gerado.")
return False
# Assume que todas as chaves do primeiro dicionário são os cabeçalhos
headers = list(devices[0].keys())
try:
with open(filename, "w", newline="", encoding="utf-8") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=headers)
# Escreve o cabeçalho
writer.writeheader()
# Escreve os dados dos dispositivos
writer.writerows(devices)
print(f"Inventário salvo com sucesso em {filename}")
return True
except Exception as e:
print(f"Erro ao gerar o arquivo CSV: {e}")
return False
# Lista de dispositivos de exemplo
network_devices = [
{"hostname": "R1", "ip": "192.168.1.1", "type": "router", "location": "DC1"},
{"hostname": "S1", "ip": "192.168.1.2", "type": "switch", "location": "DC1"},
{"hostname": "FW1", "ip": "192.168.1.254", "type": "firewall", "location": "Edge"},
{"hostname": "R2", "ip": "10.0.0.1", "type": "router", "location": "Branch1"},
{"hostname": "S2", "ip": "10.0.0.2", "type": "switch", "location": "Branch1"}
]
# Gerando o arquivo CSV
csv_output_filename = "network_inventory_output.csv"
generate_inventory_csv(network_devices, csv_output_filename)
Exercício 3: Carregador de Configuração JSON
Crie um script que leia um arquivo JSON contendo a configuração de um dispositivo (ex: hostname, lista de interfaces com IPs, lista de VLANs) e imprima as informações de forma organizada.
Solução do Exercício 3:
#!/usr/bin/env python3
# Carregador de Configuração JSON
import json
def load_and_display_json_config(filename):
"""Carrega uma configuração de dispositivo de um arquivo JSON e a exibe."""
try:
with open(filename, "r", encoding="utf-8") as jsonfile:
config_data = json.load(jsonfile)
print(f"\nConfiguração carregada de: {filename}")
print("-" * 40)
# Exibindo informações básicas
print(f"Hostname: {config_data.get("hostname", "N/A")}")
print(f"Modelo: {config_data.get("model", "N/A")}")
print(f"Versão IOS: {config_data.get("ios_version", "N/A")}")
# Exibindo Interfaces
if "interfaces" in config_data and isinstance(config_data["interfaces"], list):
print("\nInterfaces:")
for interface in config_data["interfaces"]:
name = interface.get("name", "N/A")
ip = interface.get("ip_address", "unassigned")
mask = interface.get("subnet_mask", "")
status = interface.get("status", "up")
print(f" - {name}: IP={ip}/{mask}, Status={status}")
# Exibindo VLANs
if "vlans" in config_data and isinstance(config_data["vlans"], list):
print("\nVLANs:")
for vlan in config_data["vlans"]:
vlan_id = vlan.get("id", "N/A")
vlan_name = vlan.get("name", "N/A")
print(f" - ID: {vlan_id}, Nome: {vlan_name}")
print("-" * 40)
return True
except FileNotFoundError:
print(f"Erro: Arquivo {filename} não encontrado.")
return False
except json.JSONDecodeError as e:
print(f"Erro ao decodificar JSON no arquivo {filename}: {e}")
return False
except Exception as e:
print(f"Erro ao carregar ou processar o arquivo {filename}: {e}")
return False
# Criando um arquivo JSON de configuração de exemplo
json_config_data = {
"hostname": "Switch-Core-1",
"model": "Cisco Catalyst 9300",
"ios_version": "16.9.3",
"interfaces": [
{"name": "GigabitEthernet1/0/1", "ip_address": "unassigned", "status": "up"},
{"name": "GigabitEthernet1/0/2", "ip_address": "unassigned", "status": "down"},
{"name": "Vlan10", "ip_address": "10.1.10.1", "subnet_mask": "255.255.255.0", "status": "up"},
{"name": "Vlan20", "ip_address": "10.1.20.1", "subnet_mask": "255.255.255.0", "status": "up"}
],
"vlans": [
{"id": 1, "name": "default"},
{"id": 10, "name": "Servers"},
{"id": 20, "name": "Users"},
{"id": 99, "name": "Management"}
]
}
json_config_filename = "switch_config.json"
with open(json_config_filename, "w", encoding="utf-8") as f:
json.dump(json_config_data, f, indent=4)
# Carregando e exibindo a configuração
load_and_display_json_config(json_config_filename)
Avaliação do Módulo
Quiz de Conhecimentos
Responda às seguintes perguntas para testar seu conhecimento sobre os conceitos apresentados neste módulo:
- Qual função é usada para abrir um arquivo em Python? Quais são os dois argumentos mais importantes?
- Qual é a diferença entre os modos de abertura
'w'e'a'? - Por que é importante fechar um arquivo após usá-lo?
- Qual é a maneira recomendada de garantir que um arquivo seja fechado automaticamente em Python?
- Qual método lê o conteúdo inteiro de um arquivo para uma única string?
- Qual método lê todas as linhas de um arquivo para uma lista de strings?
- Qual é a maneira mais eficiente em termos de memória para ler um arquivo grande linha por linha?
- O método
write()adiciona automaticamente uma nova linha (\n) ao final da string escrita? - Qual módulo Python é usado para trabalhar com arquivos CSV?
- Qual módulo Python é usado para trabalhar com dados JSON? Qual a função para ler de um arquivo e qual para escrever?
Respostas do Quiz:
- Função para abrir arquivo:
open(). Os dois argumentos mais importantes são o caminho do arquivo (nome) e o modo de abertura (ex: 'r', 'w', 'a'). O argumentoencodingtambém é muito importante. - Diferença entre 'w' e 'a':
'w'(write) abre o arquivo para escrita; se o arquivo existir, seu conteúdo é apagado (sobrescrito). Se não existir, é criado.'a'(append) abre o arquivo para anexar; os dados são escritos no final do arquivo. Se não existir, é criado. - Importância de fechar arquivos: Para garantir que todos os dados sejam gravados no disco, liberar recursos do sistema (descritores de arquivo) e evitar que o arquivo fique bloqueado para outros processos.
- Fechar arquivo automaticamente: Usar a instrução
with(gerenciador de contexto). Ex:with open(...) as f:. - Ler arquivo inteiro para string: O método
read()sem argumentos. - Ler todas as linhas para lista: O método
readlines(). - Ler arquivo grande linha por linha: Iterar diretamente sobre o objeto arquivo usando um laço
for. Ex:for line in file_object:. - write() adiciona nova linha? Não, o método
write()não adiciona automaticamente um caractere de nova linha. Você precisa incluir\nna string se necessário. - Módulo para CSV: O módulo
csv. - Módulo para JSON: O módulo
json. A função para ler de um arquivo éjson.load(file_object)e para escrever éjson.dump(python_object, file_object).
Projeto Prático
Desenvolva um script Python que leia um arquivo de inventário CSV, colete (simule) o status de cada dispositivo (online/offline) e gere um relatório em formato JSON contendo o status atualizado de cada dispositivo.
- Crie uma função para ler o inventário de um arquivo CSV.
- Crie uma função para simular a verificação de status de um dispositivo (pode retornar "online" ou "offline" aleatoriamente).
- Itere sobre os dispositivos lidos, verifique o status de cada um.
- Armazene os resultados (incluindo o status) em uma nova estrutura de dados (lista de dicionários).
- Crie uma função para escrever essa estrutura de dados em um arquivo JSON formatado.
Referências e Recursos Adicionais
Documentação Oficial
- Tutorial Python: Lendo e Escrevendo Arquivos
- Documentação Python: Função open()
- Documentação Python: Módulo csv
- Documentação Python: Módulo json
Livros Recomendados
- Al Sweigart - "Automate the Boring Stuff with Python" (Capítulos sobre Leitura/Escrita de Arquivos, CSV e JSON)
- Eric Matthes - "Python Crash Course" (Capítulo sobre Arquivos e Exceções)
Recursos Online
- Real Python: Reading and Writing Files in Python
- Real Python: Reading and Writing CSV Files in Python
- Real Python: Working With JSON Data in Python
- W3Schools: Python File Handling