ディスクに書き込み中に、ファイルをロックします
-
22-08-2019 - |
質問
私は2つの独立したスレッドを有するF1及びF2並列に実行されている(java.util.concurrent.FutureTaskの2つのインスタンス正確に)。
F1何らかの処理を行い、その後、XMLファイルに結果をコピーします。それは(多くのXMLファイルが作成されます)は何の関係もありませんまで続いて、これらのステップを繰り返します。 F2はF1の出力ディレクトリを検索し、1つのファイルを取り、それを解析し、その上にいくつかの処理を実行します。
このファイルからその時々、F2は切り捨てられますXMLデータを除いて、かなりかなりうまく動作します。私は不完全なXML、いくつかのXMLノードが存在しないことによって意味します。問題は、それが常にreproductibleないということである、と切り捨てているファイルは常に同じではありません。 そのため、私はF1がディスク上のファイルを書き込んでいる間に、F2が同じファイルを読み取ろうとしていることを考えています。時々、私はこの種のエラーを取得する理由です。
の私の質問の:それは完全にF2がないように、ディスク上にそれを書くために完了するまで(でも読書のための)ロックは、ファイルF1が現在書いているいくつかのメカニズムがある場合、私は疑問に思ってファイルのロックが解除されるまで、それを読むことができます。それとも私の問題を解決するために、他の方法は歓迎されます!
F1は、ファイルをこのように書いている:
try {
file = new File("some-file.xml");
FileUtils.writeStringToFile(file, xmlDataAsString);
} catch (IOException ioe) {
LOGGER.error("Error occurred while storing the XML in a file.", ioe);
}
F2は、ファイルをこのように読んでいるます:
private File getNextFileToMap() {
File path = getPath(); // Returns the directory where F1 stores the results...
File[] files = path.listFiles(new FilenameFilter() {
public boolean accept(File file, String name) {
return name.toLowerCase().endsWith(".xml");
}
});
if (files.length > 0) {
return files[0];
}
return null;
}
// Somewhere in my main method of F2
...
f = getNextFileToMap();
Node xmlNode = null;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(f);
if (doc != null) {
xmlNode = doc.getDocumentElement();
}
} catch (Exception e) {
LOGGER.error("Error while getting the XML from the file " + f.getAbsolutePath(), e);
}
解決
あなたはすでにF2で.xml
ファイルのフィルタリングをしているので、.temp
ファイルにF1出力を持って、それが最後のステップとして.xml
して名前を変更します。そうすれば、F2はF1が完全にそれを完了するまでF1を作っているファイルを無視します。
他のヒント
あなたは java.nio.channels.FileLock
見てきました> API?
簡単な解決策はよく、それは準備ができたときに(例えばfoo.xmlする)(例えばfoo.tmp)別のファイル名に書き込み、それを名前を変更することであってもよい - 名前の変更は、(ディレクトリ内の)ほとんどのオペレーティングシステム上でアトミックです、他のプロセスは、XMLファイルを見ているときにそれが完全でなければなりません。これは、ロックよりもずっと簡単である可能性が高いです。
一般的にキーワード同期するを使用してくださいオブジェクトは、ファイルを指すファイルオブジェクトが、この場合の最善のようになります:
class MyFileFactory {
private static HashMap<string,File> files = new HashMap<String,File>();
public static File get(String name) {
if (!files.keyExists(name)) {
files.put(name, new File(name));
}
return files.get(name);
}
}
// Another class
synchronized(File f = MyFileFactory::get("some-file.xml")) {
// read or write here
}