質問
XML ファイルを NFS マウントされたファイルシステムに出力する Java コードが少しあります。ファイルシステムが Samba 共有としてマウントされている別のサーバーでは、30 秒ごとに新しい XML ファイルをポーリングするプロセスが実行されています。新しいファイルが見つかった場合は、そのファイルが処理され、バックアップ ファイルとして名前が変更されます。99% の場合、ファイルは問題なく書き込まれます。ただし、バックアップ ファイルに部分的に書き込まれたファイルが含まれる場合があります。
他の何人かと議論した結果、外部サーバーで実行されているプロセスが、ファイルを読み取るときに Java 出力ストリームに干渉しているのではないかと推測しました。彼らは、最初に .temp タイプのファイルを作成し、ファイルの書き込みが完了した後にそのファイルの名前を .xml に変更することを提案しました。業界の一般的な慣例。変更後、名前の変更は毎回失敗します。
一部の調査では、NFS マウントされたファイルシステムを使用する場合、Java ファイル I/O にバグがあることが判明しました。
Java の達人を助けてください!この問題を解決するにはどうすればよいですか?
関連情報を次に示します。
- 私のプロセスは、Solaris 10 で実行されている Java 1.6.0_16 です。
- マウントされたファイルシステムは NAS です
- ポーリング プロセスを備えたサーバーは Windows Server 2003 R2 Standard、Service Pack 2 です
私のコードのサンプルは次のとおりです。
//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
解決
あなたはおそらく、新しいファイル名に完全なパスを指定する必要があります:
File newFile = new File(outputDirectory + fileName + ".xml");
他のヒント
私にはバグのようなこのルックスます:
File oldFile = new File(outputDirectory + fileName + ".temp");
File newFile = new File(fileName + ".xml");
私はこれを期待しているだろう
File oldFile = new File(outputDirectory + fileName + ".temp");
File newFile = new File(outputDirectory + fileName + ".xml");
XMLファイルの書き込みと読み取り/プロセス/名前変更タスク間の競合状態があるように一般的には、それが聞こえます。あなたが読み取り/プロセス/名前変更タスクを持つことができる唯一の1分、古いまたは似たような?
>ファイルを操作それとも、それは信号がXMLファイルへの書き込みが完了したことをことをXMLファイルから書き込みを完了すると、追加、空のファイルからJavaプログラムの書き込みを持っています。信号ファイルが存在する場合にのみお読み/プロセス/ XMLファイルの名前を変更します。そして、信号ファイルを削除します。
は、元のバグは間違いなく、ファイルへの同時アクセスの問題のように聞こえる - あなたのソリューションが働いているはずですが、別の解決策は、あまりにもあります。
たとえば、新しいファイルが検出されたときに、それは、ファイルサイズを記録X秒スリープし、その後、サイズが再起動にタイマーを一致しない場合、それので、あなたの自動読み取りプロセスにタイマーを置きます。これは、部分的なファイル転送の問題を回避すべきです。
EDIT:またはこれをチェックしますが、必ずそれは、タイムスタンプのいずれかの不正確さは、物質(最終更新以降、1分10秒を言う)
ていない古い十分だ作るために上記前とタイムスタンプを確認してください。別の方法としては、これを試してみてください
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();
このは(そのようなあなたのXMLリーダーデーモンのような)他のプログラムによる同時アクセスを防止するために、ネイティブのOSファイルロックを使用すべきである。
NFSはグリッチ限り:ファイルは、Javaの「名前の変更」を経由してファイルシステム間で移動することができません文書化「機能」(バグ)があります。それはNFSファイルシステム?
上にあるため、混乱があるかもしれません一般的にはNFSにはいくつかの情報。あなたのNFSの設定によって、ロックはなく、すべての作業と大きなNFS多くのインストールは、したがって、新しいデータは、後に、効果をキャッシュするため、予想以上に上げるかもしれない、読み取りパフォーマンスのために調整されているかもしれません。
私はあなたがファイルを作成したエフェクト、追加のデータを見てきました(これは別のマシン上で見られた)が、その後のすべてのデータが30秒遅れで登場します。
の方法により、最善の解決策は、回転ファイルスキーマです。だから、最後の1が書き込まれると想定され、1つは、以前に安全に書かれたと読み取ることができます。私は、単一のファイルで作業し、「パイプ」としてそれを使用することはありません。
あなたは、代わりに大容量のファイルが書き込まれ、適切に閉じられた後に書かれている空のファイルを使用することができます。小さな男があるのであれば、大きな男が明確に行われていたと読み取ることができます。
おそらく「名前変更操作では、あるファイルシステムから別のファイルシステムにファイルを移動できない可能性があります」が原因です。 http://java.sun.com/j2se/1.5.0/docs/api/java/io/File.html#renameTo%28java.io.File%2)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) その代わり