【问题标题】:Lock a file while writing it on the disk将文件写入磁盘时锁定文件
【发布时间】:2009-03-30 14:18:52
【问题描述】:

我有两个并行运行的独立线程 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);
}

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

【问题讨论】:

    标签: java file-io file-locking java.util.concurrent


    【解决方案1】:

    您看过java.nio.channels.FileLock API 吗?

    一个更简单的解决方案可能是写入一个不同的文件名(例如 foo.tmp),然后在它准备好时重命名它(例如 foo.xml) - 在大多数操作系统上重命名是原子的(在一个目录中),所以当其他进程看到 XML 文件时,它应该是完整的。这可能比锁定要简单得多。

    【讨论】:

    • 这可能是这个常青问题的最佳答案!非常感谢!
    【解决方案2】:

    由于您已经在 F2 中过滤 .xml 文件,因此将 F1 输出到 .temp 文件,然后将其重命名为 .xml 作为最后一步。这样,F2 将忽略 F1 正在制作的文件,直到 F1 完全完成它。

    【讨论】:

    • 呸,被打败了 6 秒……由于提到了 FileLock,我暂时留下我的答案。
    • @Jon Skeet:我也打算编辑提到锁。我们有相同的想法,只是顺序不同。
    • 为什么我要寻找一个复杂的解决方案,而有这么简单的东西呢?感谢您的想法!
    【解决方案3】:

    在公共对象上使用关键字synchronized,在这种情况下,指向文件的文件对象是最好的:

     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
     }
    

    【讨论】:

      猜你喜欢
      • 2012-11-01
      • 2013-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-13
      • 1970-01-01
      相关资源
      最近更新 更多