2012-06-28 20 views
15

Actualmente estoy trabajando en el proyecto que procesa archivos del directorio de origen en una de sus rutinas. Hay un proceso de Java que busca el directorio especificado e intenta leer y procesar archivos si existen. Los archivos son dejados de lado y se actualizan por otro proceso de terceros. La pregunta es ¿cómo puedo verificar si el archivo está completamente escrito? Intento usar file.length() pero parece que incluso si el proceso de escritura no se ha completado, devuelve el tamaño real. Tengo la sensación de que la solución debe depender de la plataforma. Cualquier ayuda sería apreciada.Comprobando si el archivo está completamente escrito

ACTUALIZACIÓN: Esta pregunta no es muy diferente a la del duplicado pero tiene una respuesta con un fragmento de código que está altamente calificado.

+3

¿Ha considerado usar bloqueos de archivos? – cklab

+0

Gracias. Comprobando esto. ¿Podemos estar seguros de que los bloqueos siempre se crean mediante el proceso de escritura? –

+2

Bueno, la noción es que si intentas obtener un bloqueo, debes obtener una excepción. También me encontré con esto: http://docs.oracle.com/javase/7/docs/api/java/io/File.html # canWrite% 28% 29 Nunca lo usaste, pero puedes probarlo para ver cómo funciona. Parece interesante. – cklab

Respuesta

9

¿El proceso de producción cierra el archivo cuando finaliza la escritura? Si es así, intentar abrir el archivo en el proceso del consumidor con un bloqueo exclusivo fallará si el proceso del productor todavía está produciendo.

+1

Los archivos se copian usando el comando rsync en Linux, así que creo que sí. Buena idea, lo intentaré ahora. –

+0

¿Podría escribir un ejemplo para ilustrar el procedimiento? –

+0

esto no es una respuesta correcta muy útil :( –

2

No creo que haya una solución general para eso. Buscar un tamaño de archivo es incorrecto, ya que algunas aplicaciones pueden establecer el tamaño del archivo antes de cualquier llamada de escritura. Una de las posibilidades es usar el bloqueo. Esto requerirá que el escritor acumule un bloqueo de escritura (o bloqueo exclusivo). Si no puede modificar el escritor, puede usar las herramientas proporcionadas por el sistema operativo, como fusor en Linux para ver si hay algún proceso que todavía acceda al archivo.

1

Si va a utilizar este código en una sola plataforma, puede usar NIO's FileLock facility. Pero lea la documentación detenidamente y tenga en cuenta que, en muchas plataformas, el bloqueo solo es orientativo.

Otro enfoque es hacer que un proceso escriba el archivo con un nombre que su proceso no reconocerá, luego cambie el nombre del archivo a un nombre reconocible cuando se complete la escritura. En la mayoría de las plataformas, la operación de cambio de nombre es atómica si el origen y el destino son del mismo volumen del sistema de archivos.

+0

Buen punto. Gracias. Lo haré si no tiene éxito con Java. Es un poco difícil cambiar el comportamiento del productor debido a algunas circunstancias. –

13

me dieron el trabajo solución:

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; 
} 

Gracias a @cklab y @Will y todos los demás que sugerían que mirar en forma "bloqueo exclusivo". Acabo de publicar el código aquí para hacer que otras personas interesadas en usarlo. Creo que la solución con el cambio de nombre sugerida por @tigran también funciona, pero la solución pura de Java es preferible para mí.

P.S. Inicialmente usé FileOutputStream en lugar de RandomAccessFile pero bloquea el archivo que se está escribiendo.

+2

Esto funciona en Winows pero no en Linux. – Nilesh

+0

@Nelish esto es raro porque lo implementé inicialmente en Linux para Linux –

+0

Bueno, lo probé en UNIX. Un winscp o ftp estaba transfiriendo archivos mientras trataba de bloquearlo y pude! – Nilesh

1

Una solución sencilla que he utilizado en el pasado para este escenario con Windows es utilizar boolean File.renameTo(File) y tratar de mover el archivo original a una carpeta de ensayo por separado:

Si es successfalse, entonces el potentiallyIncompleteFile todavía se está escribiendo en.

+0

Buena sugerencia para los usuarios de Windows, pero no es independiente de la plataforma. En Linux/Unix, puede eliminar y renombrar archivos que aún están abiertos por otros procesos. –

+1

Por eso mi respuesta dice "con Windows" y no "para todos los sistemas". – JoshDM

Cuestiones relacionadas