Molte automazioni d'ufficio iniziano con un file che arriva: lo scanner deposita un PDF in una cartella di rete, il gestionale esporta un CSV, un collega salva un documento da elaborare. Si può pianificare uno script che controlli la cartella ogni ora, ma a volte serve una reazione immediata. Una cartella sorvegliata, in inglese «watch folder», è un programma sempre attivo che si accorge di ogni nuovo file e lo elabora subito.
Due approcci: eventi o controllo periodico
I sistemi operativi offrono meccanismi che notificano le modifiche ai file: un programma si registra e riceve un avviso quando un file viene creato, modificato, spostato o eliminato. È l'approccio più efficiente, perché non consuma risorse quando non succede nulla.
L'alternativa è il controllo periodico: ogni pochi secondi lo script elenca la cartella e confronta il risultato con il giro precedente. È meno elegante ma più robusto in alcuni casi, in particolare con le cartelle di rete, dove le notifiche del sistema operativo non sempre arrivano in modo affidabile.
La libreria Python watchdog supporta entrambi, con la stessa interfaccia.
pip install watchdog
Lo scheletro di una cartella sorvegliata
import time
from pathlib import Path
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
CARTELLA = Path("C:/Scansioni/In arrivo")
class GestoreNuoviFile(FileSystemEventHandler):
def on_created(self, event):
if event.is_directory:
return
percorso = Path(event.src_path)
if percorso.suffix.lower() == ".pdf":
elabora(percorso)
osservatore = Observer()
osservatore.schedule(GestoreNuoviFile(), str(CARTELLA), recursive=False)
osservatore.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
osservatore.stop()
osservatore.join()
L'osservatore lavora in un thread separato e chiama on_created a ogni nuovo file. Il ciclo while serve solo a tenere vivo il programma. Per usare il controllo periodico basta sostituire Observer con PollingObserver, importato da watchdog.observers.polling.
Il problema del file non ancora completo
È la trappola principale. L'evento di creazione arriva nel momento in cui il file nasce, non quando è finito. Uno scanner che salva un PDF di venti pagine, o una copia da rete di un file pesante, impiega secondi a completare la scrittura. Se lo script lo apre subito, legge un file troncato e fallisce, oppure peggio, elabora un documento incompleto.
La soluzione più semplice è attendere che la dimensione si stabilizzi:
def attendi_completamento(percorso, pausa=2, tentativi=30):
dimensione_precedente = -1
for _ in range(tentativi):
try:
dimensione = percorso.stat().st_size
except FileNotFoundError:
return False
if dimensione == dimensione_precedente and dimensione > 0:
return True
dimensione_precedente = dimensione
time.sleep(pausa)
return False
Su Windows si può aggiungere un controllo ulteriore: provare ad aprire il file in scrittura. Se un altro programma lo sta ancora scrivendo, l'apertura fallisce. Alcuni sistemi adottano una convenzione ancora più pulita: chi produce il file lo scrive con un'estensione temporanea, come .tmp, e lo rinomina solo alla fine. Lo script sorveglia solo l'estensione definitiva.
Spostare i file dopo l'elaborazione
Una cartella sorvegliata ben progettata ha tre sottocartelle accanto a quella di arrivo:
| Cartella | Contenuto |
|---|---|
in_arrivo |
File appena depositati, in attesa |
elaborati |
File completati con successo |
errori |
File che hanno causato un problema |
Dopo l'elaborazione lo script sposta il file nella cartella appropriata. La cartella di arrivo resta così sempre vuota o quasi, e chiunque può capire a colpo d'occhio lo stato del lavoro. Un file in errori è un segnale chiaro che serve un intervento, mentre un file rimasto in in_arrivo da troppo tempo indica che lo script si è fermato.
Eventi duplicati e file già presenti
Alcune applicazioni, salvando un file, generano più eventi in rapida successione: creazione, poi una o più modifiche. Se lo script reagisce anche alle modifiche, rischia di elaborare lo stesso file più volte. Ascoltare solo on_created, e magari on_moved per i file rinominati, riduce il problema; tenere un insieme dei percorsi già in lavorazione lo elimina.
Va poi ricordato che l'osservatore vede solo i file creati dopo il suo avvio. Se lo script viene riavviato dopo un'interruzione, i file arrivati nel frattempo restano lì. Per questo all'avvio conviene sempre elaborare ciò che è già presente nella cartella di arrivo, prima di mettersi in ascolto.
Tenere lo script sempre attivo
Uno script lanciato a mano si ferma quando si chiude la sessione. Per un servizio permanente le opzioni sono un'attività dell'Utilità di pianificazione di Windows che parte all'avvio del computer, un servizio systemd su Linux o un piccolo server dedicato. In ogni caso serve un log su file: nel mio lavoro registro ogni file ricevuto, l'esito e il tempo impiegato, così posso ricostruire cosa è successo anche giorni dopo.
In sintesi
watchdognotifica la creazione di nuovi file;PollingObserverè più affidabile sulle cartelle di rete.- Attendete che il file sia completo prima di elaborarlo, controllando che la dimensione si stabilizzi.
- Spostate i file in cartelle
elaboratiederroriper rendere visibile lo stato. - Gestite gli eventi duplicati ed elaborate i file già presenti all'avvio.
- Eseguite lo script come servizio permanente e tenete un log dettagliato.