【问题标题】:How to lock folder in java before writing file?java - 如何在写入文件之前锁定java中的文件夹?
【发布时间】:2018-07-05 05:47:31
【问题描述】:

我有多个线程可以将文件写入文件夹的用例。在给定的时间点,我想确定哪个是该文件夹中的最新文件。 由于我不能使用时间戳,因为它可以与文件夹中的多个文件相同。所以我想锁定文件夹,通过计算文件夹中文件的数量生成序列号,使用生成的序列号写入新文件,释放锁定。这在java中可能吗?

读取时同样取序列号最大的文件。

同时将文件写入文件夹的可能性较小,因此性能不会成为问题。

【问题讨论】:

  • 您可以使用锁定文件来序列化访问。
  • 锁定文件是否也适用于文件夹?
  • 建议你自己搞清楚什么是锁文件。
  • 您不能锁定文件夹以供其他进程写入或读取(只要您不使用操作系统的功能)。但是,如果您有一个并发应用程序,您可以同步您的应用程序的线程。
  • 这个程序是唯一写入文件夹的东西,还是你也应该保护其他应用程序?该程序是否有多个实例在运行,还是只有一个进程可以使用内存锁?

标签: java file concurrency synchronization


【解决方案1】:

您不能在目录上使用FileLock,因此您必须在Java 中处理锁定问题。你可以这样做:

private final Object lock = new Object();

public void writeToNext(String dirPath) {
    synchronized(lock) {
        File dir = new File(dirPath);
        List<File> files = Arrays.asList(dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return !pathname.isDirectory();
            }
        }));

        int numFiles = files.size();
        String nextFile = dir.getAbsolutePath() + File.separator + (numFiles + 1) + ".txt"; // get a path for the new file
        System.out.println("Writing to " + nextFile);
        // TODO write to file
    }
}

注意

您可以实现您的解决方案,使得每次写入都会在某处增加一个计数器,您可以使用它来获取下一个值;如果计数器尚未初始化,则仅排序并查找最后一个文件。

【讨论】:

  • 以上锁定只会阻止线程内的并发。但在我的情况下,将有超过 1 个 java 进程写入此文件夹。
  • 您可以使用进程之间共享的资源来同步进程。例如,一个带有表的数据库,您可以从中读取以检查是否有一个进程正在处理该文件夹。如果没有为此进程输入条目,那么其他进程将知道正在处理该文件夹。
  • 文件夹中的文件数将非常少,最多 50 个。所以我认为我不需要在某处保留单独的计数器。多线程写入同一文件夹的机会也更少。不是平时活动
  • @lucio 不使用任何数据库等我们不能解决这个问题吗?为了简单起见,不想涉及任何外部系统
【解决方案2】:

使用 Java SE 7 或更高版本:

WatchService API 允许跟踪指定目录中的文件操作(创建、修改和删除文件)。在这种情况下,创建一个监视服务来跟踪在特定文件夹中创建的新文件。每次创建新文件时,都会触发文件创建事件,并且该过程允许执行一些用户定义的操作。

该文件已具有创建时间属性 (java.nio.file.attribute.BasicFileAttributes)。这可以提取为java.nio.file.attribute.FileTime 类型,它在毫秒 中,或者可以是更具体的java.util.concurrent.TimeUnit(这允许纳秒 精度)。这样可以更具体地了解最新文件是什么。

此外,还有一个选项可以为任何文件创建自定义用户定义的文件属性。该属性允许定义为键值对。这个唯一的属性值可以与一个文件相关联,以识别它是否是最新的。以下 API 允许创建和读取自定义文件属性:java.nio.file.attribute.UserDefinedFileAttributeViewFiles.getFileAttributeView()

我认为使用上述 API 和方法可以创建一个应用程序来跟踪在指定文件夹中创建的最新文件并执行所需的操作。请注意,如果使用这些 API,则不涉及锁定机制。

编辑(包括):

使用集合检索最新文件:

线程安全集合可用于存储文件名(或文件路径)并检索它们 LIFO(后进先出)。监视服务(或类似进程)可以将文件夹中创建的(最新)文件的文件名存储到此集合中。读取操作只是从该集合中获取最新的文件名并使用它。可以根据需求考虑java.util.concurrent.ConcurrentLinkedDequeLinkedBlockingDeque

编辑(包括):

一个可能的解决方案的流程图:

【讨论】:

    【解决方案3】:

    在循环中使用File.createNewFile() 进行写入。因为它

    当且仅当具有此名称的文件尚不存在时,以原子方式创建一个以此抽象路径名命名的新的空文件。检查文件是否存在并在文件不存在时创建文件是单个操作,相对于可能影响文件的所有其他文件系统活动而言是原子操作。

    像这样:

    import java.io.*;
    import java.util.*;
    
    public class FileCreator {
        public static void main(String[] args) throws IOException {
            String creatorId = UUID.randomUUID().toString();
            File dir = new File("dir");
            for (int filesCreated = 0; filesCreated < 1000; filesCreated++) {
                File newFile;
                for (int fileIdx = dir.list().length; ; fileIdx++) {
                    newFile = new File(dir, "file-" + fileIdx + ".txt");
                    if (newFile.createNewFile()) {
                        break;
                    }
                }
                try (PrintWriter pw = new PrintWriter(newFile)) {
                    pw.println(creatorId);
                }
            }
        }
    }
    

    另一个选项是Files.createFile(...)。如果文件已经存在,则抛出异常。

    至于阅读:

    读取时同样取序列号最大的文件。

    这里的问题是什么?就吧。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-18
      • 2014-12-10
      • 2021-06-13
      相关资源
      最近更新 更多