Java 在磁盘上写入文件时锁定文件

Java 在磁盘上写入文件时锁定文件,java,file-io,file-locking,java.util.concurrent,Java,File Io,File Locking,Java.util.concurrent,我有两个独立线程F1和F2(确切地说,是java.util.concurrent.FutureTask的两个实例),它们并行运行 F1执行一些处理,然后将结果复制到XML文件中。然后,它重复这些步骤,直到无事可做(创建了许多XML文件)。 F2查找F1输出目录,获取一个文件,对其进行解析,并对其执行一些处理 这非常有效,只是有时候F2会从文件中获取截断的XML数据。我的意思是一个不完整的XML,其中一些XML节点不存在。问题是它并不总是可复制的,被截断的文件也不总是相同的。 因此,我认为F1在磁

我有两个独立线程F1和F2(确切地说,是java.util.concurrent.FutureTask的两个实例),它们并行运行

F1执行一些处理,然后将结果复制到XML文件中。然后,它重复这些步骤,直到无事可做(创建了许多XML文件)。 F2查找F1输出目录,获取一个文件,对其进行解析,并对其执行一些处理

这非常有效,只是有时候F2会从文件中获取截断的XML数据。我的意思是一个不完整的XML,其中一些XML节点不存在。问题是它并不总是可复制的,被截断的文件也不总是相同的。 因此,我认为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);
}
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正在以这种方式读取文件:

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);
}
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完全处理完它。

您看过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
 }
类MyFileFactory{
私有静态HashMap文件=新HashMap();
公共静态文件获取(字符串名称){
如果(!files.keyExists(name)){
放置(名称,新文件(名称));
}
返回文件.get(名称);
}
}
//另一类
已同步(文件f=MyFileFactory::get(“some File.xml”)){
//在这里读或写
}

Bah,落后6秒。。。由于引用了FileLock,我暂时不回答。@Jon Skeet:我也打算编辑以提及锁。我们有相同的想法,只是顺序不同。为什么我要寻找一个复杂的解决方案,而有这么简单的事情?谢谢你的主意!这可能是这个常青树问题的最佳答案!谢谢!