2009-06-23 6 views
5

Ho un set di cartelle di origine. Uso una classe Java per creare il file di distribuzione da queste cartelle. Mi piacerebbe scrivere un'altra piccola classe in Java che viene eseguita ogni mezzo secondo, controlla se uno qualsiasi dei file nelle cartelle è cambiato, e se sì, esegui la classe di costruzione.Qual è il modo più semplice per tenere traccia di una modifica in una cartella in Java?

Quindi, come posso rilevare facilmente che una cartella è stata modificata?

risposta

4

Penso che sarà necessario controllare i tempi di modifica della directory e della sottodirectory (per i file aggiunti/rimossi) e i tempi di modifica del file (per le modifiche in ogni file).

Scrivere una routine ricorsiva che controlli una directory per la sua ora di modifica e se è cambiata, più ogni file. Quindi controlla il contenuto della directory e chiama in modo ricorsivo per tutte le sottodirectory. Dovresti solo essere in grado di verificare eventuali tempi di modifica maggiori rispetto a quando hai eseguito l'ultimo controllo.

Vedi File.lastModified()

EDIT: Da quando ho scritto quanto sopra, Java 7 è uscito con il suo directory watching capability.

2

Se è possibile utilizzare per utilizzare Java 7, è supportato per notifiche di modifica di directory/file indipendenti dalla piattaforma.

JNA ha un campione per notifica di cambio multipiattaforma here. Non sei sicuro di quanto potresti trovarlo facilmente.

1

Non so se va bene, ma il problema è quello di una persona, here's.

Suona come .NET ha qualcosa built-in: FileSystemWatcher

UPDATE: Grazie a kd304, ho appena saputo che Java 7 avrà la same feature. Oggi non ti farai molto bene, a meno che tu non possa usare lo preview release.

0

con NIO2 (Java7) sarà molto facile. Con Java6 puoi chiamare list() e confrontarlo con la lista precedente una volta al secondo? (Un povero servizio di guardare l'uomo)

1

devi orologio ogni file e tenere traccia dell'attributo File.lastModified e controllare la bandiera File.exists insieme con un po 'di semplice ricorsione a camminare la struttura di directory.

0

Sì, ci sono numerosi listener disponibili per le directory, ma sono tutti relativamente complicati e la maggior parte coinvolge i thread.

Pochi giorni fa sono finito in una discussione quasi riscaldata con uno dei nostri tecnici sul fatto che fosse un ammissibile la creazione di un nuovo thread (in un'applicazione web) semplicemente per monitorare un albero di directory. Alla fine sono d'accordo con lui, ma in virtù del fatto di inventare qualcosa di così veloce che non è necessario avere un ascoltatore. Nota: la soluzione descritta di seguito funziona solo se non è necessario conoscere quale file è stato modificato, solo che il file a è stato modificato.

Fornisci il seguente metodo con una raccolta di file (ad es., ottenuto tramite il metodo FileUtils.listFiles() di Apache IO e restituisce un hash per la raccolta. Se un file viene aggiunto, cancellato o modificato la sua data di modifica, l'hash cambierà.

Nei miei test, i file 50K richiedono circa 750ms su una scatola Linux 3Ghz. Toccando uno qualsiasi dei file si modifica l'hash. Nella mia implementazione sto usando un algoritmo di hash diverso (DJB) che è un po 'più veloce, ma questo è il senso. Ora archiviamo l'hash e controlliamo ogni volta perché è piuttosto semplice, soprattutto per le raccolte di file più piccole. Se qualcosa cambia, reindicizziamo la directory. La complessità di un osservatore non valeva la pena nella nostra applicazione.

/** 
* Provided a directory and a file extension, returns 
* a hash using the Adler hash algorithm. 
* 
* @param files the Collection of Files to hash. 
* @return  a hash of the Collection. 
*/ 
public static long getHash(Collection<File> files) 
{ 
    Adler32 adler = new Adler32(); 
    StringBuilder sb = new StringBuilder(); 
    for (File f : files) { 
     String s = f.getParent()+'/'+f.getName()+':'+String.valueOf(f.lastModified()); 
     adler.reset(); 
     adler.update(s.getBytes()); 
     sb.append(adler.getValue()+' '); 
    } 
    adler.reset(); 
    adler.update(sb.toString().getBytes()); 
    return adler.getValue(); 
} 

E sì, c'è spazio per migliorare (per esempio, usiamo un metodo di hash piuttosto che inlining esso). Quanto sopra è ridotto dal nostro codice attuale, ma dovrebbe darvi una buona idea di ciò che abbiamo fatto.