2012-04-05 10 views
22

Supponiamo che si abbia un processo esterno che scrive file in qualche directory e che si è verificato un processo separato che tenta periodicamente di leggere i file da questa directory. Il problema da evitare è la lettura di un file che l'altro processo è attualmente in fase di scrittura, quindi sarebbe incompleto. Attualmente, il processo che legge utilizza un controllo minimo del timer di età dei file, quindi ignora tutti i file a meno che la loro ultima data di modifica sia precedente a più di XX secondi.Come verificare se un file è "completo" (completamente scritto) con Java

Mi chiedo se esiste un modo più semplice per risolvere questo problema. Se il tipo di file è sconosciuto (potrebbe essere un numero di formati diversi) c'è un modo affidabile per verificare l'intestazione del file per il numero di byte che dovrebbero essere nel file, rispetto al numero di byte attualmente nel file per confermare che corrispondono?

Grazie per qualsiasi pensiero o idea!

+1

Avete qualche controllo sul processo di scrittura di file nella directory che sei Guardando? –

+0

A parte il rinominare il file al termine, l'approccio che prendo è quello di rendere corretto leggere il file mentre viene scritto (si pensi 'tail' in Unix) –

risposta

9

È possibile utilizzare un file di marker esterno. Il processo di scrittura potrebbe creare un file XYZ.lock prima che inizi la creazione del file XYZ e cancellare XYZ.lock dopo che XYZ è stato completato. Il lettore potrebbe quindi facilmente sapere che può considerare un file completo solo se il corrispondente file .lock non è presente.

+0

Ciao Michal, come possiamo controllare che il" file sia bloccato "attraverso il programma. –

+0

Qui, non ci sono blocchi aggiuntivi sul file - il fatto che un file esiste o meno è ciò che costituisce il blocco. –

+1

Cosa succede se non si ha il controllo sul processo di scrittura? – Matthieu

2

Anche il numero di byte è uguale, il contenuto del file potrebbe essere diverso.

Quindi penso che devi abbinare il vecchio e il nuovo file byte per byte.

1

2 opzioni che sembra risolvere questo problema:

  1. il miglior processo scrittore opzione-notificare processo di lettura in qualche modo che la scrittura era finito.
  2. scrivere il file su {id} .tmp, che al termine, rinominarlo in {id} .java e il processo di lettura viene eseguito solo sui file * .java. rinominare prendendo molto meno tempo e la possibilità che questo processo 2 lavori insieme diminuiscono.
1

In primo luogo, c'è Why doesn't OS X lock files like windows does when copying to a Samba share? ma questa è la variazione di ciò che stai già facendo.

Per quanto riguarda la lettura di file arbitrari e la ricerca di dimensioni, alcuni file hanno quell'informazione, altri no, ma anche quelli che non hanno un modo comune di rappresentarlo. Avresti bisogno di informazioni specifiche su ciascun formato e gestirli ciascuno in modo indipendente.

Se si deve assolutamente agire sul file "l'istante" è fatto, quindi il processo di scrittura dovrebbe inviare un qualche tipo di notifica. Altrimenti, sei praticamente bloccato a interrogare i file, e leggere la directory è abbastanza economico in termini di I/O rispetto alla lettura di blocchi casuali da file casuali.

8

Il modo in cui l'ho fatto in passato è che il processo che scrive il file viene scritto in un file "temp", quindi sposta il file nella posizione di lettura al termine della scrittura del file.

Quindi il processo di scrittura dovrebbe scrivere su info.txt.tmp. Al termine, rinomina il file in info.txt. Il processo di lettura ha quindi dovuto verificare l'esistenza di info.txt - e sa che se esiste, è stato scritto completamente.

In alternativa è possibile avere il processo di scrittura scrivere informazioni.txt in una directory diversa, quindi spostalo nella directory di lettura se non ti piace usare estensioni di file strani.

2

Una soluzione semplice che ho usato in passato per questo scenario con Windows è quello di utilizzare boolean File.renameTo(File) e tentare di spostare il file originale in una cartella di gestione temporanea separata:

Se success è false, poi la potentiallyIncompleteFile è ancora in fase di scrittura.

2

Non ho avuto alcuna possibilità di utilizzare i marcatori temporanei ecc. Poiché i file vengono caricati dai client su SFIP a coppia chiave. possono essere di dimensioni molto grandi.

È piuttosto hacky ma confronto la dimensione del file prima e dopo aver dormito alcuni secondi.

Il suo, ovviamente, non è l'ideale per bloccare il filo, ma nel nostro caso si tratta semplicemente di esecuzione come processi di sistema sfondo così sembra funzionare bene

private boolean isCompletelyWritten(File file) throws InterruptedException{ 
    Long fileSizeBefore = file.length(); 
    Thread.sleep(3000); 
    Long fileSizeAfter = file.length(); 

    System.out.println("comparing file size " + fileSizeBefore + " with " + fileSizeAfter); 

    if (fileSizeBefore.equals(fileSizeAfter)) { 
     return true; 
    } 
    return false; 
} 

Nota: potrebbe non funzionare su Windows, come indicato di sotto di questo. Questo è stato usato in un ambiente Linux.

+0

Unico punto di errore sarebbe un arresto di rete – Skynet

+0

Questo codice non funzionerà poiché i metadati della dimensione del file vengono scritti come primo passaggio in Windows. Quindi sempre il file.length() è lo stesso – debugger89

0

Questo è possibile utilizzando il metodo Apache Commons IO della libreria Maven FileUtils.copyFile(). Se si tenta di copiare il file e ottenere IOException significa che il file non è stato completamente salvato.

Esempio:

public static void copyAndDeleteFile(File file, String destinationFile) { 

    try { 
     FileUtils.copyFile(file, new File(fileDirectory)); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     copyAndDeleteFile(file, fileDirectory, delayThreadPeriod); 
    } 

o periodicamente verificare con una certa dimensione ritardo di cartella che contiene il file:

FileUtils.sizeOfDirectory(folder); 
+0

È interessante come i Commons IO siano in grado di tracciare questo. Quindi probabilmente risponderebbe alla domanda originale senza una copia complicata prima. – Thomas

Problemi correlati