2010-02-15 18 views
19

Ho un processo che verrà chiamato piuttosto frequentemente da cron per leggere un file che contiene determinati comandi relativi allo spostamento. Il mio processo deve leggere e scrivere su questo file di dati e tenerlo bloccato per evitare che altri processi lo tocchino durante questo periodo. Un processo completamente separato può essere eseguito da un utente per scrivere/aggiungere (potenziale) a questo stesso file di dati. Voglio che questi due processi funzionino bene e accedano al file solo uno alla volta.Java FileLock per lettura e scrittura

Il nio FileLock sembrava essere quello di cui avevo bisogno (a meno di scrivere i miei file di tipo semaforo), ma ho problemi a bloccarlo per la lettura. Posso bloccare e scrivere bene, ma quando tento di creare il blocco durante la lettura ottengo una NonWritableChannelException. È anche possibile bloccare un file per la lettura? Sembra che un RandomAccessFile sia più vicino a quello di cui ho bisogno, ma non vedo come implementarlo.

Qui è il codice che non riesce:

FileInputStream fin = new FileInputStream(f); 
FileLock fl = fin.getChannel().tryLock(); 
if(fl != null) 
{ 
    System.out.println("Locked File"); 
    BufferedReader in = new BufferedReader(new InputStreamReader(fin)); 
    System.out.println(in.readLine()); 
      ... 

L'eccezione viene generata sulla linea FileLock.

java.nio.channels.NonWritableChannelException 
at sun.nio.ch.FileChannelImpl.tryLock(Unknown Source) 
at java.nio.channels.FileChannel.tryLock(Unknown Source) 
at Mover.run(Mover.java:74) 
at java.lang.Thread.run(Unknown Source) 

Guardando le JavaDocs, si dice

eccezione incontrollato generata quando viene effettuato un tentativo di scrivere su un canale che non è stato originariamente aperto per la scrittura.

Ma non ho necessariamente bisogno di scriverlo. Quando provo a creare un FileOutpuStream, ecc. Per scopi di scrittura, sono felice finché non provo ad aprire FileInputStream sullo stesso file.

+0

Hai provato a utilizzare la chiamata al metodo tre param, blocco FileLock (posizione lunga, dimensione lunga, condivisione booleana)? Non ho mai usato il FileLock prima quindi non posterò come risposta, ma penso che usare quella chiamata di metodo possa essere d'aiuto dato che sembra che tu abbia bisogno di un blocco condiviso e non di un blocco esclusivo dal momento che vuoi scrivere sul file mentre ha un blocco su di esso. – ChadNC

+0

Penso che l'intento sia quello di bloccare solo porzioni di un file, tuttavia vorrei bloccare l'intero file per prevenire e il possibile danneggiamento. – bobtheowl2

risposta

16

(a) Sei consapevole che il blocco del file non impedirà a altri processi di toccarlo a meno che non utilizzino anche i lucchetti?
(b) È necessario bloccare tramite un canale scrivibile. Ottenere il blocco tramite un RandomAccessFile in modalità "rw" e quindi aprire il FileInputStream. Assicurati di chiudere entrambi!

+1

a) Sì, scriverò entrambi i processi e pianifico di implementare procedure di blocco simili in entrambi b) Non mi ero reso conto che si poteva ottenere direttamente il blocco su RandomAccessFile. Per utilizzare il flusso [Input | Output] del file ho avuto bisogno di fare un nuovo FileInputStream (raf.getFD()). Ma, in entrambi i casi, usando direttamente il flusso di input dell'oggetto RandomAccessFile, posso ancora leggere dal file. Grazie – bobtheowl2

+0

Eh? (a) non puoi ottenere un blocco direttamente da RandomAccessFile, devi prima ottenere il suo FileChannel; (b) RandomAccessFile non ha flussi di input, ma implementa DataInput in modo da poterlo leggere direttamente. – EJP

10

Sarebbe meglio se si fosse creato il blocco utilizzando tryLock(0L, Long.MAX_VALUE, true).

Questo crea un blocco condiviso che è la cosa giusta da fare per la lettura.

tryLock() è una scorciatoia per tryLock(0L, Long.MAX_VALUE, false), vale a dire richiede un blocco di scrittura esclusivo.

+0

Ottima risposta. Questo programma è già attivo, ma questo potrebbe sicuramente essere aggiornato nella fase successiva.Ne stiamo vedendo moltissimo ora che le serrature esclusive diventano ingombranti in alcuni scenari. Lo terrò sicuramente presente per il prossimo aggiornamento. – bobtheowl2

+0

Perché dici che un blocco condiviso è la cosa giusta da fare per la lettura, sicuramente dipende dal tuo caso d'uso? Se voglio assicurarmi che solo 1 di un certo numero di processi legga un file (ad esempio agenti che monitorano una directory di upload per elaborare nuovi file), allora non penso che un blocco condiviso sia ciò di cui ho bisogno. – codebox

+1

L'ho scritto così perché la lettura non si escludono a vicenda. In realtà è possibile che diversi thread leggano da un file senza interferire mentre la scrittura è sempre esclusiva. Tieni presente che questa era una risposta alla domanda originale e non è intesa come una verità assoluta per ogni situazione. È vero nel 99% dei casi d'uso, però. – Huxi