Pregunta

Tengo un poco de código Java que produce un archivo XML en un sistema de archivos NFS montado. En otro servidor que tiene el sistema de ficheros montado como un recurso compartido de Samba, hay un proceso en ejecución que las encuestas de nuevo archivos XML cada 30 segundos. Si se encuentra un nuevo archivo, se procesa y luego renombrado como un archivo de copia de seguridad. 99% de las veces, los archivos se escriben sin un problema. Sin embargo, de vez en cuando el archivo de copia de seguridad contiene un archivo escrito parcialmente.

Después de alguna discusión con otras personas, se supuso que el proceso que se ejecuta en el servidor externo estaba interfiriendo con el flujo de salida de Java cuando se lee el archivo. Sugirieron crear primero un archivo de .temp tipo que luego se cambió el nombre a .xml después de que el archivo de escritura es completa. Una práctica común en la industria. Después del cambio, el cambio de nombre falla cada vez.

Algunas investigaciones se presentó ese archivo Java I / O está libre de errores cuando se trabaja con sistemas de archivos NFS montado.

Me ayudan Java gurús! ¿Cómo puedo solucionar este problema?

Aquí hay alguna información relevante:

  • Mi proceso es Java 1.6.0_16 que se ejecutan en Solaris 10
  • Montado sistema de archivos es un NAS
  • Servidor de un proceso de votación es Windows Server 2003 R2 Standard, Service Pack 2

Este es un ejemplo de mi código:

//Write the file
XMLOutputter serializer = new XMLOutputter(Format.getPrettyFormat());
FileOutputStream os = new FileOutputStream(outputDirectory + fileName + ".temp");
serializer.output(doc, os);//doc is a constructed xml document using JDOM
os.flush();
os.close();

//Rename the file
File oldFile = new File(outputDirectory + fileName + ".temp");
File newFile = new File(fileName + ".xml");
boolean success = oldFile.renameTo(newFile);
if (!success) {
    // File was not successfully renamed.
    throw new IOException("The file " + fileName + ".temp could not be renamed.");
}//if
¿Fue útil?

Solución

Es probable que tenga que especificar la ruta completa en el nuevo nombre de archivo:

File newFile = new File(outputDirectory + fileName + ".xml");

Otros consejos

Esto parece un error a mí:

File oldFile = new File(outputDirectory + fileName + ".temp");
File newFile = new File(fileName + ".xml");

Me hubiera esperado esto:

File oldFile = new File(outputDirectory + fileName + ".temp");
File newFile = new File(outputDirectory + fileName + ".xml");

En general, parece que existe una condición de carrera entre la escritura del archivo XML y la tarea de lectura / proceso / cambio de nombre. sólo se puede tener la tarea de lectura / proceso / renombrar operar en archivos> 1 minuto de edad o algo similar?

O, tiene el programa de escritura de Java a cabo un archivo adicional, vacío una vez que ha terminado de escribir el archivo XML que las señales de que la escritura en el archivo XML se ha completado. Sólo lectura / proceso / cambiar el nombre del archivo XML cuando el archivo de señal presente. A continuación, elimine el archivo de señales.

El error original, definitivamente suena como un problema con el acceso simultáneo al archivo - su solución debería haber funcionado, pero hay soluciones alternativas también.

Por ejemplo, poner un temporizador en su proceso de auto-lectura por lo que cuando se detecta un nuevo archivo que registra tamaño del archivo, duerme X segundos, y luego, si los tamaños no coinciden reinicia el temporizador. Eso debería evitar problemas con la transferencia de archivos parcial.

EDIT:. O detectar las marcas de tiempo como pre anterior para comprobar esto, pero asegúrese de que sea lo suficientemente mayor que cualquier imprecisión en la marca de tiempo no importa (ejemplo, 10 segundos a 1 minuto desde la última modificación)

Como alternativa, intente esto:

File f = new File("foo.xml");
FileOutputStream fos = new FileOutputStream(f);
FileChannel fc = fos.getChannel();
FileLock lock = fc.lock();
(DO FILE WRITE)
fis.flush();
lock.release();
fos.close();

Esto es conveniente utilizar el bloqueo de archivos nativo OS para evitar el acceso simultáneo por otros programas (como su lector de XML demonio).

En lo que NFS glitches: hay un documentado "característica" (bug) donde los archivos no se pueden mover entre sistemas de archivos a través de "cambio de nombre" en Java. ¿Podría haber confusión, ya que está en un sistema de archivos NFS?

Parte de la información de NFS en general. Dependiendo de la configuración de NFS, cerraduras podría no funcionar en absoluto y una gran cantidad de grandes instalaciones NFS están sintonizados para un rendimiento de lectura, por lo tanto, nuevos datos podrían aparecer más tarde de lo esperado, debido a los efectos de caché.

Me han visto efectos donde se crea un archivo, los datos agregados (esto fue visto en otra máquina), pero todos los datos después de que se presentó con un retraso de 30 seg.

La mejor solución por cierto es un esquema de archivo de rotación. De manera que el último se supone que está escrita y el anterior fue escrito de forma segura y se puede leer. No trabajaría en un solo archivo y utilizarlo como un "tubo".

Se puede utilizar alternativamente un archivo vacío que se escribe después de que el archivo de gran tamaño fue escrito y bien cerrada. Así que si los chicos pequeños está ahí, el gran hombre se hizo definitivamente y se puede leer.

Posiblemente debido a "la operación de cambio de nombre podría no ser capaz de mover un archivo de un sistema de archivos a otro" de http://java.sun.com/j2se/1.5.0/docs/api/java/io/File html # renameTo% 28java.io.File% 2 ) Trate de usar Apache Commons io FiltUtils.copyFileToDirectory http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#copyFileToDirectory (java.io.File, % 20java.io.File) lugar

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top