Java WatchService未正确轮询

Java WatchService未正确轮询,java,nio,watchservice,Java,Nio,Watchservice,我想每10秒轮询一个目录,看看是否有任何文件被添加或修改。如果它们在10秒内有任何更改,我希望有一组可以传递给另一个方法的所有文件路径 问题 添加文件时,会立即识别该文件,并调用addedFiles方法。相反,我希望它等待10秒钟,并使用找到的多个文件调用addedFiles方法 示例 我创建了一个监视目录的完整示例。然后线程等待5秒钟,将2000个文件复制到监视的目录中。 监视服务的预期行为是每10秒检查一次更改。相反,它似乎正在立即接受变化 代码 import java.io.IOExcep

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

问题

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

示例
我创建了一个监视目录的完整示例。然后线程等待5秒钟,将2000个文件复制到监视的目录中。
监视服务的预期行为是每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)
    {

    }
}
import java.io.IOException;
导入java.io.PrintWriter;
导入java.nio.file.FileSystems;
导入java.nio.file.Path;
导入java.nio.file.path;
导入java.nio.file.StandardWatchEventTypes;
导入java.nio.file.WatchEvent;
导入java.nio.file.WatchKey;
导入java.nio.file.WatchService;
导入java.util.Collection;
导入java.util.HashSet;
导入java.util.concurrent.TimeUnit;
公共类DirectoryWatcher示例
{
专用静态最终整数轮询时间=10;
公共静态void main(最终字符串args[])引发InterruptedException,IOException
{
final Path directory=Path.get(“directory/to/be/watched”);
/**
*启动一个线程,该线程将在所选目录中创建2000个文件
*这将在等待5秒后发生。
*/
新线程(newrunnable())
{
@凌驾
公开募捐
{
尝试
{
睡眠(5000);
System.out.println(“将2000个文件复制到目录:“+目录”);
对于(int i=0;i<2000;i++)
{
final PrintWriter=new PrintWriter(directory.resolve(“test_file_“+i+”.txt”).toFile(),“UTF-8”);
writer.println(“第一行”);
writer.println(“第二行”);
writer.close();
}
System.out.println(“已完成将文件复制到目录:“+目录”);
} 
捕获(最终异常e)
{
e、 printStackTrace();
} 
}
}).start();
/**
*每10秒启动一次watch服务轮询
*/
新建DirectoryWatcherExample().startWatchService(目录);
}
public void startWatchService(最终路径目录)引发InterruptedException,IOException
{
final WatchService WatchService=FileSystems.getDefault().newWatchService();
注册(watchService、StandardWatchEventTypes.ENTRY\u创建、StandardWatchEventTypes.ENTRY\u修改);
while(true)
{
System.out.println(“开始轮询”);
最终WatchKey=watchService.poll(轮询时间,时间单位为秒);
System.out.println(“完成轮询并检索密钥”);
if(key!=null)
{
最终收集路径=新HashSet();
for(最终WatchEvent WatchEvent:key.pollEvents())
{
最终路径路径=((路径)key.watchable()).resolve((路径)watchEvent.context());
路径。添加(路径);
System.out.println(“添加路径:“+Path”);
}
//对路径做点什么
添加文件(路径);
如果(!key.reset())
{
打破
}   
}
}
}
//未执行
公共无效添加文件(最终收集路径)
{
}
}

这可能是什么原因造成的

WatchService.poll(timeout,unit)
中的timeout参数不用于定义它必须延迟多长时间。它仅定义最大等待时间(之后返回是否检测到事件)

它仍然会在检测到更改后立即返回。阅读

检索并删除下一个监视键,如果需要等待,直到指定的等待时间(如果尚未出现)

没有任何地方写着它会一直等待那么久。

有两种选择:

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

  • 或者,您可能希望使用ApacheCommons IO文件监视库。它会根据需要轮询文件系统。您甚至可以设置轮询间隔

  • 请参阅以下三个类/接口:

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

    你可以考虑为你的用例做的是,不断添加所有的文件细节。