Operazioni sicure sui file con gestione degli errori
Verifica dell’esistenza e dei permessi dei file e gestione corretta degli errori di I/O
Operazioni sicure sui file con gestione degli errori è una lezione AI Agents gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Agents, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Agents include 4 lezioni in totale.
Perché sono importanti le operazioni sicure sui file
Le operazioni sui file negli agenti possono fallire in molti modi: il file non esiste, l'agente non dispone delle autorizzazioni necessarie, il percorso è una directory oppure lo spazio su disco si esaurisce durante la scrittura. Un agente che si arresta a causa di un errore sui file lascia un output parziale e uno stato corrotto. La programmazione difensiva, con controlli e gestione corretta degli errori, rende gli agenti più resilienti.
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() e Path.is_file()
Prima di leggere un file, verifichi che esista e che sia effettivamente un file regolare (non una directory, un collegamento simbolico a una directory o un file speciale). Path.exists() restituisce True per qualsiasi oggetto del filesystem; Path.is_file() restituisce True solo per i file regolari.
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() — Verifica dei permessi
os.access(path, mode) verifica se il processo corrente dispone del permesso specificato su un file. Utilizzi os.R_OK per la lettura, os.W_OK per la scrittura e os.X_OK per l'esecuzione. È utile prima di tentare operazioni che richiedono permessi specifici.
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')Gestione di FileNotFoundError
FileNotFoundError (una sottoclasse di OSError) viene sollevata quando si tenta di aprire un file inesistente. La gestisca in modo esplicito e fornisca un messaggio di errore utile che includa il percorso previsto, così l'utente o l'operatore saprà esattamente cosa manca.
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}')
Gestione di PermissionError
PermissionError viene sollevata quando il processo non dispone dei permessi per leggere o scrivere un file. Può accadere con i file di sistema, con i file di proprietà di un altro utente o con i file dotati di permessi restrittivi. Gestisca sempre questa eccezione separatamente da FileNotFoundError: richiedono risposte diverse.
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'))
Gestione di IsADirectoryError
IsADirectoryError viene sollevata quando si tenta di aprire una directory come se fosse un file. Può accadere quando un agente costruisce un percorso in modo errato, ad esempio aggiungendo un nome file che esiste già come directory. Gestisca sempre questa eccezione per fornire un output significativo.
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}')
Scritture atomiche con tempfile
La scrittura diretta in un file è rischiosa: se l'agente si arresta durante la scrittura, il file rimane scritto solo parzialmente e si corrompe. La soluzione è una scrittura atomica: scriva prima in un file temporaneo, quindi lo rinomini nel percorso finale. La rinomina è atomica sui sistemi POSIX: il file finale contiene sempre la versione precedente o quella nuova, mai una versione parziale.
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'))
Blocco dei file per agenti concorrenti
Quando più istanze di un agente vengono eseguite in parallelo e scrivono nello stesso file, le race condition corrompono i dati. Utilizzi il blocco dei file con il modulo fcntl (Linux/macOS) oppure la libreria multipiattaforma filelock per impedire scritture simultanee.
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 NoneEliminazione sicura con controlli di esistenza
L'eliminazione di un file inesistente solleva FileNotFoundError. L'eliminazione di una directory con Path.unlink() solleva IsADirectoryError. Utilizzi Path.unlink(missing_ok=True) (Python 3.8+) oppure verifichi prima l'esistenza per eliminare i file in sicurezza.
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')Controllo dello spazio su disco prima della scrittura
Gli agenti che scrivono file di grandi dimensioni (output dell'IA, dataset, log) dovrebbero verificare prima lo spazio disponibile su disco. shutil.disk_usage(path) restituisce i byte totali, utilizzati e liberi. Verifichi che lo spazio libero superi le dimensioni previste dell'output prima di avviare un'operazione di scrittura prolungata.
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)Backup prima della sovrascrittura
Quando un agente aggiorna un file esistente, è consigliabile conservare un backup della versione precedente. In questo modo è possibile ripristinare la versione precedente se il nuovo contenuto è errato. Utilizzi un nome file di backup con timestamp e limiti il numero di backup per evitare di esaurire lo spazio su 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.*'))])
Verifica rapida: scritture atomiche
Verifichi di aver compreso i modelli sicuri per la scrittura dei file.
Riepilogo delle operazioni sicure sui file
Ora i Suoi agenti possono gestire i file in modo più sicuro:
- Verificare prima di accedere:
Path.exists()+Path.is_file()+os.access(path, os.R_OK) - Gestire FileNotFoundError, PermissionError e IsADirectoryError con messaggi chiari
- Utilizzare scritture atomiche (tempfile + os.replace) per impedire la creazione di file parziali o corrotti in caso di arresto anomalo
- Utilizzare il blocco dei file (libreria filelock) quando più agenti scrivono nello stesso file
- Utilizzare missing_ok=True per eliminare i file in sicurezza senza sollevare FileNotFoundError
- Verificare lo spazio su disco prima delle scritture di grandi dimensioni e conservare backup prima di sovrascrivere file importanti
Domande Frequenti
La lezione «Operazioni sicure sui file con gestione degli errori» è gratuita?
Sì — il testo completo di «Operazioni sicure sui file con gestione degli errori» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Agents, passa a CoddyKit PRO. Il corso AI Agents include 4 lezioni in totale.
Cosa imparerò in «Operazioni sicure sui file con gestione degli errori»?
Verifica dell’esistenza e dei permessi dei file e gestione corretta degli errori di I/O Eserciti AI Agents con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare AI Agents?
Non è richiesta alcuna esperienza precedente. AI Agents su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Operazioni sicure sui file con gestione degli errori»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione AI Agents?
Sì. Ogni lezione AI Agents include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Lettura e scrittura dei file nel contesto degli agenti
- Attraversamento delle directory e ricerca dei file
- Gestione dei formati file: CSV, JSON e TXT
- Operazioni sicure sui file con gestione degli errori