将文件写入磁盘时锁定文件

发布于 2024-07-16 06:07:57 字数 1624 浏览 3 评论 0原文

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

I have two independant threads F1 and F2 (to be precise, two instances of java.util.concurrent.FutureTask) that are running in parallel.

F1 do some processing, and then copy the result in a XML file. Then, it repeats these steps until it has nothing to do (many XML files are created).
F2 looks in the F1 output directory, and take one file, parse it, and execute some processing on it.

This works quite pretty well, except that sometimes, F2 gets truncated XML data from the file. I mean by that an incomplete XML, where some XML node are not present. The problem is that it is not always reproductible, and the files that are truncated are not always the same.
Because of that, I am thinking that while F1 is writing one file on the disk, F2 is trying to read the same file. That's why sometimes I get this kind of error.

My question: I am wondering if there is some mechanism that locks (even for reading) the file F1 is currently writing until it has completely finished to write it on the disk, so F2 will not be able to read it until the file is unlocked. Or any other way to solve my issue will be welcome !

F1 is writing the file this way:

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 is reading the file this way:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

_失温 2024-07-23 06:07:57

您是否看过 java.nio .channels.FileLock API?

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

Have you looked at the java.nio.channels.FileLock API?

A simpler solution may well be to write to a different filename (e.g. foo.tmp) and then rename it (e.g. to foo.xml) when it's ready - the rename is atomic on most operating systems (within a directory), so when the other process sees the XML file it should be complete. This is likely to be a lot simpler than locking.

剩余の解释 2024-07-23 06:07:57

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

Since you're already filtering for .xml files in F2, have F1 output to a .temp file, then rename it to .xml as a final step. That way, F2 will ignore the file F1 is making until F1 is completely done with it.

当梦初醒 2024-07-23 06:07:57

在公共对象上使用关键字 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
 }

Use the keyword synchronized on a common object, a File Object pointing to the file would be the best in this case:

 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
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文