锁定文件,同时在磁盘上写它
-
22-08-2019 - |
题
我有两个独立的线程F1和F2(准确地,java.util.concurrent.FutureTask中的两个实例),该并行运行。
F1做一些处理,并随后在XML文件中的结果复制。然后,重复这些步骤,直到它无关(创建许多XML文件)。 F2看在F1输出目录,并采取一个文件,分析它,并在其上执行一些处理。
这工作得很好,除了从文件中,有时,F2被截断的XML数据。我的意思是说一个不完整的XML,一些XML节点不存在。问题是,它并不总是reproductible,而被截断的文件并不总是相同的。 正因为如此,我想,虽然F1在磁盘上写入一个文件,F2是试图读取相同的文件。这就是为什么有时我得到这样的错误的。
我的提问:我想知道是否有一些机制,锁(甚至读)的文件F1目前正在写,直到它已经完全结束将它写在磁盘上,因此F2不会能够阅读它,直到该文件被解锁。或任何其他方式来解决我的问题将受到欢迎!
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
文件过滤,有F1输出到.temp
文件,然后重命名为.xml
作为最后一步。这样一来,F2将忽略该文件F1正在直到F1是完全用它做。
其他提示
你有没有看了 java.nio.channels.FileLock
一> API?
一个简单的解决方案可能是写入到不同的文件名(例如foo.tmp),然后将其重命名(例如,到foo.xml)当它准备 - 重命名是在大多数操作系统原子(一个目录内),所以,当其他进程看到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
}
不隶属于 StackOverflow