2010-02-15 17 views
19

Tengo un proceso que se llamará con bastante frecuencia de cron para leer un archivo que tiene ciertos comandos relacionados con movimiento en él. Mi proceso necesita leer y escribir en este archivo de datos y mantenerlo bloqueado para evitar que otros procesos lo toquen durante este tiempo. Un proceso completamente independiente puede ser ejecutado por un usuario para (potencial) escribir/anexar a este mismo archivo de datos. Quiero que estos dos procesos jueguen bien y solo accedan al archivo de a uno por vez.Java FileLock para leer y escribir

El nio FileLock parecía ser lo que necesitaba (salvo escribir mis propios archivos de tipo de semáforo), pero tengo problemas para bloquearlo y leerlo. Puedo bloquear y escribir muy bien, pero cuando intento crear un bloqueo al leer, obtengo una NonWritableChannelException. ¿Es posible bloquear un archivo para leer? Parece que RandomAccessFile está más cerca de lo que necesito, pero no veo cómo implementarlo.

Aquí está el código que falla:

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()); 
      ... 

La excepción se produce en la línea 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) 

En cuanto a los JavaDocs, que dice

excepción no comprobada lanzado cuando se hace un intento de escribir en un canal que no se abrió originalmente para la escritura.

Pero no necesariamente necesito escribir en él. Cuando intento crear un FileOutpuStream, etc. para fines de escritura, me alegro hasta que intento abrir FileInputStream en el mismo archivo.

+0

¿Ha intentado utilizar la llamada al método de tres param, bloqueo de FileLock (posición larga, tamaño largo, booleano compartido)? Nunca utilicé FileLock antes, así que no publicaré una respuesta, pero creo que usar ese método puede ser útil ya que parece que necesita un bloqueo compartido y no un bloqueo exclusivo, ya que desea escribir en el archivo mientras tiene un candado. – ChadNC

+0

Creo que la intención de esto es bloquear solo partes de un archivo; sin embargo, me gustaría bloquear todo el archivo para evitar posibles daños. – bobtheowl2

Respuesta

16

(a) ¿Sabía que bloquear el archivo no evitará que otros procesos lo toquen a menos que también usen bloqueos?
(b) Tiene que bloquear a través de un canal grabable. Obtenga el bloqueo a través de un RandomAccessFile en modo "rw" y luego abra su FileInputStream. ¡Asegúrate de cerrar ambos!

+1

a) sí, escribiré ambos procesos y planeo implementar procedimientos de bloqueo similares en ambos b) No me di cuenta de que podría obtener el bloqueo en RandomAccessFile directamente. Para usar el Archivo [Entrada | Salida] Stream, necesitaba hacer un nuevo FileInputStream (raf.getFD()). Pero, en cualquier caso, al utilizar la secuencia de entrada del objeto RandomAccessFile directamente, aún puedo leer desde el archivo. Gracias – bobtheowl2

+0

¿Eh? (a) no puede obtener un candado directamente de RandomAccessFile, primero debe obtener su FileChannel; (b) RandomAccessFile no tiene flujos de entrada, pero implementa DataInput para que pueda leer directamente. – EJP

10

Sería mejor si creó la cerradura usando tryLock(0L, Long.MAX_VALUE, true).

Esto crea un bloqueo compartido que es lo correcto para leer.

tryLock() es una abreviatura de tryLock(0L, Long.MAX_VALUE, false), es decir, solicita un bloqueo de escritura exclusivo.

+0

Gran respuesta. Este programa ya está en vivo, pero sin duda podría actualizarse en la siguiente fase.Estamos viendo tanto uso ahora que los bloqueos exclusivos se vuelven engorrosos en ciertos escenarios. Definitivamente voy a tener esto en cuenta para la próxima actualización. – bobtheowl2

+0

¿Por qué dices que un bloqueo compartido es lo correcto para leer, seguramente eso depende de tu caso de uso? Si deseo asegurarme de que solo 1 de una serie de procesos lee un archivo (por ejemplo, agentes que supervisan un directorio de carga para procesar archivos nuevos), entonces no creo que sea necesario un bloqueo compartido. – codebox

+1

Lo escribí así porque la lectura no es mutuamente excluyente. En realidad, es posible que varios hilos se lean de un archivo sin interferir, mientras que la escritura es siempre exclusiva. Tenga en cuenta que esta fue una respuesta a la pregunta original y no pretende ser una verdad absoluta para cada situación. Sin embargo, es cierto en el 99% de los casos de uso. – Huxi

Cuestiones relacionadas