Domanda

Ho un po 'di codice Java che genera un file XML per un NFS filesystem. Su un altro server che ha il filesystem montato come una condivisione Samba, c'è un processo in esecuzione che i sondaggi per il nuovo XML file ogni 30 secondi. Se viene rilevato un nuovo file, esso viene elaborato e poi rinominato come file di backup. Il 99% del tempo, i file vengono scritti senza un problema. Tuttavia, di tanto in tanto il file di backup contiene un file parzialmente scritta.

Dopo qualche discussione con altre persone, abbiamo intuito che il processo in esecuzione sul server esterno è stata interferire con il flusso di output Java quando leggere il file. Hanno suggerito prima creazione di un file di tipo .temp che sarà poi rinominato .xml dopo che il file di scrittura è completo. Una pratica comune nell'industria. Dopo la modifica, la ridenominazione non riesce ogni volta.

Alcune ricerche alzato quel file Java I / O è buggy quando si lavora con NFS montato file system.

Aiutami guru Java! Come posso risolvere questo problema?

Ecco alcune informazioni rilevanti:

  • Il mio processo è Java 1.6.0_16 in esecuzione su Solaris 10
  • filesystem montato è un NAS
  • Server con le procedure di polling è Windows Server 2003 R2 Standard, il Service Pack 2

Ecco un esempio del mio codice:

//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
È stato utile?

Soluzione

Probabilmente è necessario specificare il percorso completo nel nuovo nome del file:

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

Altri suggerimenti

Questo appare come un bug a me:

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

mi sarei aspettato questo:

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

In generale, sembra che ci sia una condizione di competizione tra la scrittura del file XML e di lettura / processo / rinominare compito. Si può avere la lettura / processo / rinominare compito operare solo su file> 1 minuto vecchio o qualcosa di simile?

In alternativa, avere il programma Java scrivere un file aggiuntivo, vuoto una volta che ha completato la scrittura di file XML che segnala che la scrittura per il file XML è stata completata. Solo lettura / processo / rinominare il file XML quando il file segnale è presente. Quindi eliminare il file di segnale.

Il bug originale suona decisamente come un problema con l'accesso simultaneo al fascicolo - la soluzione dovrebbe avere lavorato, ma ci sono soluzioni alternative troppo.

Per esempio, mettere un timer sul vostro processo di auto-lettura in modo che quando viene rilevato un nuovo file registra la dimensione del file, dorme X secondi, e poi se le dimensioni non corrispondono riavvia il timer. Questo dovrebbe evitare problemi con il trasferimento di file parziale.

EDIT: o controllare i timestamp come pre qui sopra per verificare questo, ma assicurarsi che sia abbastanza grande che qualsiasi imprecisione il timestamp non ha importanza (ad esempio, 10 secondi a 1 minuto dall'ultima modifica)

.

In alternativa, provate questo:

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

Questo dovrebbe utilizzare nativo blocco dei file del sistema operativo per impedire l'accesso simultaneo da parte di altri programmi (come il tuo lettore di XML daemon).

Per quanto riguarda i difetti NFS: c'è una "caratteristica" documentata (bug) dove i file non possono essere spostati tra le file system tramite "rinomina" in Java. Potrebbe esserci confusione, dal momento che è su un filesystem NFS?

Alcune informazioni per NFS in generale. A seconda delle impostazioni NFS, serrature potrebbero non funzionare a tutti e un sacco di grandi installazioni NFS sono sintonizzati per prestazioni di lettura, quindi, i nuovi dati potrebbero alzare più tardi del previsto, a causa di effetti di cache.

Ho visto gli effetti cui è stato creato un file, i dati aggiunti (questo è stato visto su un'altra macchina), ma tutti i dati dopo che è apparso con un ritardo di 30 secondi.

La migliore soluzione tra l'altro è uno schema di file rotante. In modo che l'ultimo si presume essere scritto e quello prima era al sicuro scritta e può essere letto. Non vorrei lavorare su un singolo file e utilizzarlo come "pipe".

È possibile in alternativa utilizzare un file vuoto che viene scritto dopo il file di grandi dimensioni è stato scritto e chiuso correttamente. Quindi, se i piccoli ragazzi è lì, il pezzo grosso è stato definitivamente fatto e può essere letto.

Forse a causa di "L'operazione di ridenominazione potrebbe non essere in grado di spostare un file da un file system a un altro" da http://java.sun.com/j2se/1.5.0/docs/api/java/io/File .html # renameTo% 28java.io.File% 2 ) Provare a utilizzare beni comuni apache io FiltUtils.copyFileToDirectory http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#copyFileToDirectory (java.io.File, % 20java.io.File) invece

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top