我想每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)
{
}
}
可能是什么原因造成的?
答案 0 :(得分:1)
WatchService.poll(timeout, unit)
中的timeout参数不是用于定义必须延迟多长时间。它仅定义了最长等待时间(此后将返回是否检测到事件)。
一旦检测到更改,它仍会返回。阅读JavaDoc for WatchService.poll
检索并删除下一个监视键,如果需要的话,等待直到指定的等待时间。
没有写到它总是会等待那么长时间。
答案 1 :(得分:1)
有两种选择:
您需要在一定间隔后通过在poll
上进行睡眠来调用watchService
。正如其他人指出的那样,poll
方法中的超时适用于缓冲区中没有事件可用的情况。另外,由于您没有立即处理事件,因此某些事件可能会使操作系统缓冲区溢出并最终丢失。因此,您还需要处理溢出情况。
或者,您可能要使用Apache Commons IO文件监视库。它将根据需要轮询文件系统。您甚至可以设置轮询间隔。
请参阅以下三个类/接口here:
FileAlterationMonitor
-基本上是一个线程(一种Runnable
实现),它在轮询间隔内休眠,并且在每个间隔之后调用FileAlterationObserver
FileAlterationObserver
-它列出目录中的文件,将当前列表与上一个列表进行比较,识别文件更改并在FileAlterationListener
实现中调用适当的方法FileAlterationListener
-实现和编写逻辑所需的接口您可能会考虑为用例做的事情,是在添加或修改文件时将所有文件详细信息不断添加到列表中。最后,在调用onStop()
方法时,将使用完整列表调用addedFiles
方法,清除列表,然后重新开始。