Operaciones seguras con archivos y gestión de errores
Compruebe la existencia y los permisos de los archivos y gestione los errores de E/S correctamente.
Operaciones seguras con archivos y gestión de errores es una lección gratuita de AI Agents en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AI Agents, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AI Agents incluye 4 lecciones en total.
Por qué son importantes las operaciones seguras con archivos
Las operaciones con archivos en los agentes pueden fallar de muchas formas: el archivo no existe, el agente no tiene permisos, la ruta corresponde a un directorio o el espacio en disco se agota durante la escritura. Un agente que falla ante un error de archivo deja una salida parcial y un estado dañado. La programación defensiva, con comprobaciones y gestión de errores adecuadas, hace que los agentes sean resistentes.
from pathlib import Path
# Unsafe: crashes with FileNotFoundError
# content = Path('missing.txt').read_text()
# Safe: check first
path = Path('config.json')
if path.exists():
content = path.read_text(encoding='utf-8')
print('Loaded config')
else:
print(f'Config not found at {path.resolve()}')
content = '{}' # use defaultPath.exists() y Path.is_file()
Antes de leer un archivo, compruebe que existe y que realmente es un archivo normal (no un directorio, un enlace simbólico a un directorio ni un archivo especial). Path.exists() devuelve True para cualquier objeto del sistema de archivos; Path.is_file() devuelve True únicamente para archivos normales.
from pathlib import Path
path = Path('data/report.csv')
# Chain of checks
if not path.exists():
print(f'Not found: {path}')
elif not path.is_file():
print(f'Not a regular file: {path} (is_dir={path.is_dir()})')
elif path.stat().st_size == 0:
print(f'File is empty: {path}')
else:
# Safe to read
import csv
with open(path, 'r', encoding='utf-8', newline='') as f:
reader = csv.DictReader(f)
rows = list(reader)
print(f'Read {len(rows)} rows')os.access() — Comprobación de permisos
os.access(path, mode) comprueba si el proceso actual tiene el permiso especificado sobre un archivo. Use os.R_OK para lectura, os.W_OK para escritura y os.X_OK para ejecución. Esto resulta útil antes de intentar operaciones que requieren permisos específicos.
import os
from pathlib import Path
def check_file_access(path):
p = Path(path)
checks = {
'exists': p.exists(),
'is_file': p.is_file(),
'readable': os.access(p, os.R_OK),
'writable': os.access(p, os.W_OK),
}
for check, result in checks.items():
status = 'OK' if result else 'FAIL'
print(f' {check}: {status}')
return all(checks.values())
if check_file_access('data/input.json'):
print('File is accessible')
else:
print('Access problem — check path and permissions')Captura de FileNotFoundError
FileNotFoundError (una subclase de OSError) se produce cuando intenta abrir un archivo que no existe. Captúrela explícitamente y proporcione un mensaje de error útil que incluya la ruta esperada, para que el usuario o el operador sepa exactamente qué falta.
import json
from pathlib import Path
def load_agent_config(config_path='agent_config.json'):
path = Path(config_path)
try:
with open(path, 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
print(f'Config file not found: {path.resolve()}')
print('Create agent_config.json with your settings')
print('Example: {"model": "gpt-4o", "max_retries": 3}')
return {} # return empty config as default
except json.JSONDecodeError as e:
print(f'Invalid JSON in {path}: {e}')
return {}
# --- demo ---
config = load_agent_config('does_not_exist_config.json')
print(f'Config used: {config}')
Captura de PermissionError
PermissionError se produce cuando el proceso no tiene permiso para leer o escribir un archivo. Esto puede ocurrir con archivos del sistema, archivos propiedad de otro usuario o archivos con permisos restrictivos. Captúrela siempre por separado de FileNotFoundError, ya que requieren respuestas diferentes.
from pathlib import Path
def read_file_safely(path):
try:
return Path(path).read_text(encoding='utf-8')
except FileNotFoundError:
print(f'File not found: {path}')
return None
except PermissionError:
import os
print(f'Permission denied: {path}')
print(f'File permissions: {oct(Path(path).stat().st_mode)}')
print(f'Current user: {os.getlogin()}')
print('Try: chmod +r ' + str(path))
return None
except IsADirectoryError:
print(f'Path is a directory, not a file: {path}')
return None
# --- demo ---
import os
print(read_file_safely('does_not_exist.txt'))
os.makedirs('a_directory', exist_ok=True)
print(read_file_safely('a_directory'))
Captura de IsADirectoryError
IsADirectoryError se produce cuando intenta abrir un directorio como si fuera un archivo. Esto puede ocurrir cuando un agente construye una ruta incorrectamente, por ejemplo, al añadir un nombre de archivo que ya existe como directorio. Captúrela siempre para proporcionar una salida de error significativa.
from pathlib import Path
def safe_write(output_path, content):
path = Path(output_path)
# Check the path is not an existing directory
if path.is_dir():
raise IsADirectoryError(
f'Cannot write file: {path} is a directory. '
f'Use a filename like {path}/output.txt instead.'
)
# Ensure parent directory exists
path.parent.mkdir(parents=True, exist_ok=True)
try:
path.write_text(content, encoding='utf-8')
print(f'Written: {path} ({len(content)} chars)')
except IsADirectoryError as e:
print(f'Path error: {e}')
except PermissionError:
print(f'Cannot write to {path} — permission denied')
# --- demo ---
import os
safe_write('demo_output/report.txt', 'Agent finished the task.')
os.makedirs('already_a_dir', exist_ok=True)
try:
safe_write('already_a_dir', 'this will fail')
except IsADirectoryError as e:
print(f'Rejected: {e}')
Escrituras atómicas con tempfile
Escribir directamente en un archivo es peligroso: si el agente se bloquea durante la escritura, el archivo queda escrito parcialmente y se corrompe. La solución es una escritura atómica: escriba primero en un archivo temporal y, después, cámbiele el nombre para convertirlo en la ruta final. El renombrado es atómico en los sistemas POSIX: el archivo final será siempre la versión anterior o la nueva, nunca una versión parcial.
import tempfile
import os
import json
from pathlib import Path
def atomic_write_json(file_path, data):
path = Path(file_path)
path.parent.mkdir(parents=True, exist_ok=True)
# Write to temp file in same directory
tmp_fd, tmp_path = tempfile.mkstemp(
dir=path.parent,
prefix='.tmp_',
suffix='.json'
)
try:
with os.fdopen(tmp_fd, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
# Atomic rename: replaces final file in one operation
os.replace(tmp_path, path)
print(f'Atomically wrote: {path}')
except Exception as e:
os.unlink(tmp_path) # clean up temp file on error
raise
# --- demo ---
atomic_write_json('demo_state/state.json', {'step': 3, 'status': 'running'})
print('File contents:', Path('demo_state/state.json').read_text(encoding='utf-8'))
Bloqueo de archivos para agentes simultáneos
Cuando varias instancias de un agente se ejecutan en paralelo y escriben en el mismo archivo, las condiciones de carrera corrompen los datos. Use el bloqueo de archivos con el módulo fcntl (Linux/macOS) o la biblioteca multiplataforma filelock para evitar escrituras simultáneas.
from filelock import FileLock, Timeout
import json
from pathlib import Path
COUNTER_FILE = Path('shared_counter.json')
LOCK_FILE = Path('shared_counter.json.lock')
def increment_counter():
lock = FileLock(str(LOCK_FILE), timeout=10)
try:
with lock:
# Only one process can be here at a time
if COUNTER_FILE.exists():
data = json.loads(COUNTER_FILE.read_text())
else:
data = {'count': 0}
data['count'] += 1
COUNTER_FILE.write_text(
json.dumps(data, indent=2)
)
return data['count']
except Timeout:
print('Could not acquire lock within 10 seconds')
return NoneEliminación segura con comprobaciones de existencia
Eliminar un archivo inexistente produce FileNotFoundError. Eliminar un directorio con Path.unlink() produce IsADirectoryError. Use Path.unlink(missing_ok=True) (Python 3.8+) o compruebe primero si existe para eliminarlo de forma segura.
from pathlib import Path
import shutil
# Safe file deletion (Python 3.8+)
Path('temp_output.json').unlink(missing_ok=True)
# Safe directory deletion
def safe_remove(path):
p = Path(path)
if not p.exists():
print(f'Already gone: {p}')
return
if p.is_file():
p.unlink()
print(f'Deleted file: {p}')
elif p.is_dir():
shutil.rmtree(p)
print(f'Deleted directory: {p}')
else:
print(f'Unknown file type: {p}')
# Clean up temporary workspace
safe_remove('/tmp/agent_workspace/run_001')Comprobación del espacio en disco antes de escribir
Los agentes que escriben archivos grandes (resultados de IA, conjuntos de datos o registros) deben comprobar primero el espacio disponible en disco. shutil.disk_usage(path) devuelve los bytes totales, usados y libres. Compruebe que el espacio libre supere el tamaño esperado de los resultados antes de iniciar una operación de escritura prolongada.
import shutil
from pathlib import Path
def check_disk_space(output_dir, required_bytes):
path = Path(output_dir)
path.mkdir(parents=True, exist_ok=True)
usage = shutil.disk_usage(path)
free_gb = usage.free / (1024 ** 3)
required_gb = required_bytes / (1024 ** 3)
print(f'Disk free: {free_gb:.2f} GB')
print(f'Required: {required_gb:.2f} GB')
if usage.free < required_bytes * 1.1: # 10% safety margin
raise IOError(
f'Insufficient disk space: '
f'{free_gb:.2f} GB free, '
f'{required_gb:.2f} GB required'
)
return True
# Before writing a 500 MB dataset
check_disk_space('/tmp/output', 500 * 1024 * 1024)Copia de seguridad antes de sobrescribir
Cuando un agente actualiza un archivo existente, es recomendable conservar una copia de seguridad de la versión anterior. Esto permite revertir los cambios si el nuevo contenido es incorrecto. Use un nombre de archivo de copia de seguridad con marca de tiempo y limite el número de copias para evitar llenar el espacio en disco.
import shutil
import datetime
from pathlib import Path
def write_with_backup(file_path, content, max_backups=5):
path = Path(file_path)
backup_dir = path.parent / '.backups'
backup_dir.mkdir(exist_ok=True)
# Backup existing file
if path.exists():
timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
backup = backup_dir / f'{path.name}.{timestamp}'
shutil.copy2(path, backup)
print(f'Backed up to: {backup}')
# Write new content
path.write_text(content, encoding='utf-8')
# Prune old backups
backups = sorted(backup_dir.glob(f'{path.name}.*'))
for old in backups[:-max_backups]:
old.unlink()
print(f'Pruned old backup: {old.name}')
# --- demo ---
write_with_backup('demo_notes.txt', 'version 1')
write_with_backup('demo_notes.txt', 'version 2')
print('Backups:', [p.name for p in sorted(Path('.backups').glob('demo_notes.txt.*'))])
Comprobación rápida: escrituras atómicas
Compruebe su comprensión de los patrones seguros de escritura de archivos.
Resumen de operaciones seguras con archivos
Sus agentes ya pueden gestionar archivos de forma preventiva:
- Compruebe antes de acceder:
Path.exists()+Path.is_file()+os.access(path, os.R_OK) - Capture FileNotFoundError, PermissionError e IsADirectoryError con mensajes claros
- Use escrituras atómicas (tempfile + os.replace) para evitar archivos parciales o dañados si se produce un bloqueo
- Use el bloqueo de archivos (biblioteca filelock) cuando varios agentes escriban en el mismo archivo
- Use missing_ok=True para eliminar de forma segura sin producir FileNotFoundError
- Compruebe el espacio en disco antes de realizar escrituras grandes; conserve copias de seguridad antes de sobrescribir archivos importantes
Preguntas frecuentes
¿La lección «Operaciones seguras con archivos y gestión de errores» es gratis?
Sí — el texto completo de «Operaciones seguras con archivos y gestión de errores» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AI Agents, actualiza a CoddyKit PRO. El curso de AI Agents incluye 4 lecciones en total.
¿Qué aprenderé en «Operaciones seguras con archivos y gestión de errores»?
Compruebe la existencia y los permisos de los archivos y gestione los errores de E/S correctamente. Practicas AI Agents con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar AI Agents?
No se requiere experiencia previa. AI Agents en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Operaciones seguras con archivos y gestión de errores»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de AI Agents?
Sí. Cada lección de AI Agents incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Lectura y escritura de archivos en el contexto de un agente
- Recorrido de directorios y descubrimiento de archivos
- Gestión de formatos de archivo: CSV, JSON y TXT
- Operaciones seguras con archivos y gestión de errores