2012-06-28 18 views
15

Attualmente sto lavorando al progetto che elabora i file dalla directory sorgente in una delle sue routine. C'è un processo Java che cerca la directory specificata e tenta di leggere ed elaborare i file se esistono. I file vengono abbandonati e gli aggiornamenti vengono eseguiti da altri processi di terze parti. La domanda è: come posso verificare se il file è stato scritto completamente? Sto cercando di usare file.length() ma sembra che anche se il processo di scrittura non è stato completato, restituisce le dimensioni reali. Ho la sensazione che la soluzione dovrebbe essere dipendente dalla piattaforma. Qualsiasi aiuto sarebbe apprezzato.Verifica se il file è completamente scritto

AGGIORNAMENTO: Questa domanda non è molto diversa dal duplicato ma ha una risposta con lo snippet di codice funzionante che ha un punteggio elevato.

+3

Hai considerato l'utilizzo di blocchi di file? – cklab

+0

Grazie. Controllando questo Possiamo essere sicuri che i blocchi vengano sempre creati tramite il processo di scrittura? –

+2

Bene, il concetto è che se si tenta di ottenere un blocco, si dovrebbe ottenere un'eccezione. Mi sono imbattuto anche in questo: http://docs.oracle.com/javase/7/docs/api/java/io/File.html # canWrite% 28% 29 Mai usato, ma puoi dare un colpo per vedere come funziona. Sembra interessante. – cklab

risposta

9

Il processo del produttore chiude il file al termine della scrittura? In tal caso, provare ad aprire il file nel processo consumatore con un blocco esclusivo avrà esito negativo se il processo produttore continua a produrre.

+1

I file vengono copiati usando il comando rsync sotto linux quindi credo che lo faccia. Bella idea, proverò ora. –

+0

Potresti scrivere un esempio per illustrare la procedura? –

+0

questa non è una risposta corretta molto utile :( –

2

Non penso che ci sia una soluzione generale per questo. La ricerca di una dimensione del file è errata in quanto alcune applicazioni possono impostare la dimensione del file prima di qualsiasi chiamata di scrittura. Una delle possibilità è usare il blocco. Ciò richiederà che lo scrittore accumuli un blocco di scrittura (o blocco esclusivo). Se non è possibile modificare il writer, è possibile utilizzare gli strumenti forniti dal sistema operativo, come il fuser su Linux, per vedere se esiste un processo che accede al file.

1

Se si prevede di utilizzare questo codice su una singola piattaforma, è possibile utilizzare NIO's FileLock facility. Ma leggi attentamente la documentazione e nota che su molte piattaforme il blocco è solo di consulenza.

Un altro approccio prevede che un processo scriva il file con un nome che il processo non riconoscerà, quindi rinominerà il file con un nome riconoscibile al termine della scrittura. Sulla maggior parte delle piattaforme, l'operazione di rinomina è atomica se l'origine e la destinazione sono lo stesso volume del file system.

+0

Buon punto Grazie. Lo farò se non ha successo con java È un po 'difficile cambiare il comportamento del produttore a causa di alcune circostanze –

13

ho ottenuto il lavoro soluzione:

private boolean isCompletelyWritten(File file) { 
    RandomAccessFile stream = null; 
    try { 
     stream = new RandomAccessFile(file, "rw"); 
     return true; 
    } catch (Exception e) { 
     log.info("Skipping file " + file.getName() + " for this iteration due it's not completely written"); 
    } finally { 
     if (stream != null) { 
      try { 
       stream.close(); 
      } catch (IOException e) { 
       log.error("Exception during closing file " + file.getName()); 
      } 
     } 
    } 
    return false; 
} 

Grazie alla @cklab e @Will e tutti gli altri che ha suggerito di guardare in modo "blocco esclusivo". Ho appena postato il codice qui per far sì che altri interessati alla gente lo usino. Credo che la soluzione con la rinomina suggerita da @tigran funzioni anche se per me è preferibile una soluzione Java pura.

P.S. Inizialmente ho utilizzato FileOutputStream anziché RandomAccessFile ma blocca il file in fase di scrittura.

+2

Questo funziona su Winows ma non su Linux – Nilesh

+0

@Nelish questo è strano perché inizialmente l'ho implementato su Linux per Linux –

+0

Beh, l'ho provato su UNIX. Un winscp o ftp stava trasferendo il file mentre provavo a bloccare e sono riuscito a! – Nilesh

1

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.

+0

Un buon suggerimento per gli utenti Windows, ma non è indipendente dalla piattaforma. Su Linux/Unix puoi cancellare e rinominare i file che sono ancora aperti da altri processi. –

+1

Ecco perché la mia risposta dice "con Windows" e non "per tutti i sistemi". – JoshDM

Problemi correlati