java - WatchService 轮询不正确

标签 java nio watchservice

我想每 10 秒轮询一个目录,看看是否有任何文件被添加或修改。如果它们在 10 秒内有任何变化,我想要一组所有文件路径,然后我可以将其传递给另一个方法。

问题

添加文件后,它会立即被识别并调用 addedFiles 方法。相反,我希望它等待 10 秒,然后使用已找到的多个文件调用 addedFiles 方法。

例子
我创建了一个监视目录的完整示例。然后一个线程等待 5 秒并将 2000 个文件复制到监视目录中。
WatchService 的预期行为是每 10 秒检查一次更改。相反,它似乎正在立即获取更改。

代码

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.TimeUnit;

public class DirectoryWatcherExample 
{
    private static final int POLLING_TIME = 10;

    public static void main(final String args[]) throws InterruptedException, IOException
    {
        final Path directory = Paths.get("directory/to/be/watched");

        /**
         * Start a thread that will create 2000 files to the selected directory
         * This will occur after waiting 5 seconds.
         */
        new Thread(new Runnable()
        {
            @Override
            public void run() 
            {
                try 
                {
                    Thread.sleep(5000);         
                    System.out.println("Copying 2000 files to directory: " + directory);
                    for(int i = 0; i < 2000; i++)
                    {
                        final PrintWriter writer = new PrintWriter(directory.resolve("test_file_" + i + ".txt").toFile(), "UTF-8");
                        writer.println("The first line");
                        writer.println("The second line");
                        writer.close();
                    }
                    System.out.println("Finished copying files to directory: " + directory);
                } 
                catch (final Exception e) 
                {
                    e.printStackTrace();
                } 
            }
        }).start();

        /**
         * Start the watch service polling every 10 seconds
         */
        new DirectoryWatcherExample().startWatchService(directory);
    }

    public void startWatchService(final Path directory) throws InterruptedException, IOException
    {
        final WatchService watchService = FileSystems.getDefault().newWatchService();
        directory.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY);

        while(true)
        {
            System.out.println("Start polling");
            final WatchKey key = watchService.poll(POLLING_TIME, TimeUnit.SECONDS);
            System.out.println("Finished polling and retrieved key");

            if(key != null)
            {
                final Collection<Path> paths = new HashSet<>();
                for (final WatchEvent<?> watchEvent : key.pollEvents())
                {
                    final Path path = ((Path) key.watchable()).resolve((Path) watchEvent.context());
                    paths.add(path);
                    System.out.println("Path added: " + path);
                }

                // Do something with the paths
                addedFiles(paths);

                if (!key.reset())
                {
                    break;
                }   
            }

        }
    }

    // Unimplemented
    public void addedFiles(final Collection<Path> paths)
    {

    }
}

这可能是什么原因造成的?

最佳答案

有两种选择:

  1. 您需要在特定时间间隔后通过 hibernate 在 watchService 上调用 poll。正如其他人指出的那样,poll 方法中的超时适用于缓冲区中没有可用事件的情况。此外,由于您没有立即处理事件,因此某些事件可能会溢出操作系统缓冲区并最终丢失。因此,您还需要处理溢出情况。

  2. 或者,您可能想要使用 Apache Commons IO 文件监控库。它会根据需要轮询文件系统。您甚至可以设置轮询间隔。

引用以下三个类/接口(interface)here :

  • FileAlterationMonitor - 它基本上是一个线程(Runnable 实现),它在轮询间隔内 hibernate 并在每个间隔调用后调用 FileAlterationObserver
  • FileAlterationObserver - 它列出目录中的文件,将当前列表与先前列表进行比较,识别文件更改并调用 FileAlterationListener 实现中的适当方法
  • FileAlterationListener - 您需要实现和编写逻辑的接口(interface)

您可能会考虑为您的用例做的是,在添加或修改文件详细信息时继续将所有文件详细信息添加到列表中。最后,当 onStop() 方法被调用时,您使用完整列表调用您的 addedFiles 方法,清除列表并重新开始。

关于java - WatchService 轮询不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53435608/

相关文章:

java - 使用 Ebean NullPointerException 玩 2.4

java - 如何修复缺少 Artifact 的 POM?

Java WatchService 不适用于某些文件夹

Java 7 WatchService - 文件打开时触发 ENTRY_MODIFY

JAVA System.out.println 方程

java - Java NIO 是否支持广播或多播?

Java 7 - LinkOption - 为什么 NOFOLLOW_LINKS 是唯一可用的选项?

Java 套接字 : can I write a TCP server with one thread?

java - 在java中使用WatchService检测文件完成情况

java - Nexus 服务未正常运行