繁体   English   中英

Java 文件夹/文件手表

[英]Java Folder/File watch

我正在尝试构建一个监视文件夹及其子文件夹以检测文件创建或修改的应用程序。 要观看的文件总数将每天增加。

我曾尝试使用 java nio WatchService 和 apache 常见的 FileAlterationObserver。 WatchService 有时会在使用 WatchKey 后重置之前发生文件创建/修改时丢失事件。 由于 FileAlterationObserver 基于轮询,因此当文件数增加时,性能也会下降。

构建这样一个应用程序的最佳方法是什么?

谢谢@DuncG。 在浏览了提到的示例后,我找到了解决问题的方法。

如果有人面临同样的问题,请添加此示例代码。

在示例中,我将所有事件添加到一个集合中(这将删除重复的事件)并在 WatchKey 为空后处理保存的事件。 在处理保存的事件时,新目录将注册到 WatchService。

package com.filewatcher;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class WatchService implements Runnable {

private static final long POLL_DELAY = 3;

private static final Logger LOGGER = LoggerFactory.getLogger(WatchService.class);

private final WatchService watcher;

private final Map<WatchKey, Path> keys;

private final Set<Path> events = new HashSet<Path>();

public WatchService(Path dir) throws IOException {
    this.watcher = FileSystems.getDefault().newWatchService();
    this.keys = new HashMap<WatchKey, Path>();
    walkAndRegisterDirectories(dir);
}

@Override
public void run() {
    while (true) {
        try {
            WatchKey key;
            try {
                key = watcher.poll(POLL_DELAY, TimeUnit.SECONDS);
            } catch (InterruptedException x) {
                return;
            }

            if (key != null) {
                Path root = keys.get(key);
                for (WatchEvent<?> event : key.pollEvents()) {
                    Path eventPath = (Path) event.context();
                    if (eventPath == null) {
                        System.out.println(event.kind());
                        continue;
                    }

                    Path fullPath = root.resolve(eventPath);
                    events.add(fullPath);
                }

                boolean valid = key.reset();
                if (!valid) {
                    keys.remove(key);
                }
            } else {
                if (events.size() > 0) {
                    processEvents(events);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/**
 * Process events and register new directory with watch service
 * @param events
 * @throws IOException
 */
private void processEvents(Set<Path> events) throws IOException {
    for (Path path : events) {
        // register directory with watch service if its not already registered
        if (Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS) && !this.keys.containsValue(path)) {
            registerDirectory(path);
            // Since new directory was not registered, get all files inside the directory.
            // new/modified files after this will get notified by watch service
            File[] files = path.toFile().listFiles();
            for (File file : files) {
                LOGGER.info(file.getAbsolutePath());
            }
        } else {
            LOGGER.info(path.toString());
        }
    }
    // clear events once processed
    events.clear();
}

/**
 * Register a directory and its sub directories with watch service
 * @param root folder
 * @throws IOException
 */
private void walkAndRegisterDirectories(final Path root) throws IOException 
{
    Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
            registerDirectory(dir);
            return FileVisitResult.CONTINUE;
        }
    });
}

/**
 * Register a directory with watch service
 * @param directory
 * @throws IOException
 */
  private void registerDirectory(Path dir) throws IOException {
    WatchKey key = dir.register(this.watcher, StandardWatchEventKinds.ENTRY_CREATE,
            StandardWatchEventKinds.ENTRY_MODIFY);
    this.keys.put(key, dir);
  }
}

public class FileWatcherApplication implements CommandLineRunner {
    @Value("${filewatch.folder}")
    private String rootPath;

    public static void main(String[] args) {
        SpringApplication.run(FileWatcherApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        File rootFolder = new File(rootPath);
        if (!rootFolder.exists()) {
            rootFolder.mkdirs();
        }

        new Thread(new WatchService(Paths.get(rootPath)), "WatchThread").start();
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM