Question

J'ai un peu de code Java qui génère un fichier XML à un système de fichiers NFS monté. Sur un autre serveur qui a le système de fichier monté en partage Samba, il y a un processus en cours d'exécution que les sondages fichiers XML pour le nouveau toutes les 30 secondes. Si un nouveau fichier est trouvé, il est traité puis renommé en tant que fichier de sauvegarde. 99% du temps, les fichiers sont écrits sans problème. Cependant, chaque maintenant et puis le fichier de sauvegarde contient un fichier partiellement écrit.

Après discussion avec d'autres personnes, nous avons deviné que le processus en cours d'exécution sur le serveur externe interférait avec le flux de sortie Java quand il a lu le fichier. Ils ont suggéré d'abord la création d'un fichier de type .temp qui sera ensuite renommé .xml après l'écriture de fichier est terminé. Une pratique courante dans l'industrie. Après le changement, le changement de nom échoue à chaque fois.

Des recherches tournées vers le haut ce fichier Java I / O est bogué lorsque vous travaillez avec des systèmes de fichiers NFS monté.

Aidez-moi Java gourous! Comment puis-je résoudre ce problème?

Voici quelques informations pertinentes:

  • Mon processus est Java 1.6.0_16 en cours d'exécution sur Solaris 10
  • système de fichiers est monté un NAS
  • Serveur avec le processus de vote est Windows Server 2003 R2 Standard, Service Pack 2

Voici un exemple de mon code:

//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
Était-ce utile?

La solution

Vous avez probablement de spécifier le chemin complet dans le nouveau nom de fichier:

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

Autres conseils

Cela ressemble à un bug pour moi:

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

Je me serais attendu à ceci:

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

En général, il sonne comme il y a une condition de course entre l'écriture du fichier XML et de lecture / processus / renommer la tâche. Pouvez-vous avoir la lecture / processus / renommer la tâche ne fonctionne que sur les fichiers> 1 minute vieux ou quelque chose de similaire?

Ou, ont le programme Java écrire un fichier supplémentaire, vide une fois qu'il a terminé d'écrire le fichier XML qui signale que l'écriture dans le fichier XML est terminé. Seulement lecture / processus / renommer le fichier XML lorsque le fichier de signal est présent. Ensuite, supprimez le fichier de signal.

Le bug d'origine sonne vraiment comme un problème avec l'accès simultané au fichier - votre solution aurait dû fonctionner, mais il existe d'autres solutions aussi.

Par exemple, mettre une minuterie sur votre processus de lecture automatique donc quand un nouveau fichier est détecté, il enregistre la taille du fichier, dort X secondes, puis si les tailles ne correspondent pas à l'horloge redémarre. Cela devrait éviter les problèmes de transfert de fichier partiel.

EDIT: ou vérifier les horodateurs comme avant ci-dessus pour vérifier, mais assurez-vous qu'il est assez vieux que toute imprécision dans l'horodatage n'a pas d'importance (par exemple 10 secondes à 1 minute depuis la dernière modification)

.

Sinon, essayez ceci:

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

DEVRAIT utiliser le verrouillage de fichier natif OS pour empêcher l'accès simultané par d'autres programmes (tels que votre démon lecteur XML).

En ce qui concerne NFS: glitches il y a un (bug) « fonction » documentée où les fichiers ne peuvent pas être déplacés entre les systèmes de fichiers via « renommer » en Java. Y aurait-il une confusion, car il est sur un système de fichiers NFS?

Quelques informations à NFS en général. En fonction de vos paramètres NFS, serrures ne fonctionnent pas du tout et beaucoup de grandes installations NFS sont à l'écoute pour des performances de lecture, donc de nouvelles données pourraient se présenter plus tard que prévu, en raison des effets de mise en cache.

J'ai vu des effets où vous avez créé un fichier, ajouté des données (ce qui a été vu sur une autre machine), mais toutes les données après qui est apparu avec un retard de 30 secondes.

La meilleure solution par la voie est un schéma de fichier rotatif. Alors que le dernier est supposé être écrit et celui d'avant a été écrit en toute sécurité et peut être lu. Je ne voudrais pas travailler sur un seul fichier et l'utiliser comme un « tuyau ».

Vous pouvez également utiliser un fichier vide qui est écrit après le grand fichier a été écrit et fermé. Donc, si les petits gars est là, le grand gars a été définitivement fait et peut être lu.

Peut-être en raison de « L'opération de changement de nom pourrait ne pas être en mesure de déplacer un fichier d'un système de fichiers à un autre » http://java.sun.com/j2se/1.5.0/docs/api/java/io/File .html # renameTo% 28java.io.File% 2 ) Essayez d'utiliser communes apache io FiltUtils.copyFileToDirectory http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#copyFileToDirectory (java.io.File, % 20java.io.File) place

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top