Java 如何查看文件夹和子文件夹的更改

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18701242/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 10:18:37  来源:igfitidea点击:

How to watch a folder and subfolders for changes

javawatchservice

提问by Yuri Heupa

I′m trying to watch a specific folder for changes, and then if any addition/edition/removal happens inside of it, I need to get the change type of all files in that folder and its subfolders. I'm using WatchServicefor this but it only watches a single path, it doesn't handle subfolders.

我正在尝试查看特定文件夹的更改,然后如果其中发生任何添加/编辑/删除,我需要获取该文件夹及其子文件夹中所有文件的更改类型。我正在使用WatchService它,但它只监视一条路径,它不处理子文件夹。

Here's my approach:

这是我的方法:

try {
        WatchService watchService = pathToWatch.getFileSystem().newWatchService();
        pathToWatch.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
                StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);

        // loop forever to watch directory
        while (true) {
            WatchKey watchKey;
            watchKey = watchService.take(); // This call is blocking until events are present

            // Create the list of path files
            ArrayList<String> filesLog = new ArrayList<String>();
            if(pathToWatch.toFile().exists()) {
                File fList[] = pathToWatch.toFile().listFiles();
                for (int i = 0; i < fList.length; i++) { 
                    filesLog.add(fList[i].getName());
                }
            }

            // Poll for file system events on the WatchKey
            for (final WatchEvent<?> event : watchKey.pollEvents()) {
                printEvent(event);
            }

            // Save the log
            saveLog(filesLog);

            if(!watchKey.reset()) {
                System.out.println("Path deleted");
                watchKey.cancel();
                watchService.close();
                break;
            }
        }

    } catch (InterruptedException ex) {
        System.out.println("Directory Watcher Thread interrupted");
        return;
    } catch (IOException ex) {
        ex.printStackTrace();  // Loggin framework
        return;
    }

Like I said before, I'm getting the log only for the files in the selected path, and I want to watch all folders and subfolders files, something like:

就像我之前说的,我只获取所选路径中文件的日志,我想查看所有文件夹和子文件夹文件,例如:

Example 1:

示例 1:

FileA (Created)
FileB
FileC
FolderA FileE
FolderA FolderB FileF

Example 2:

示例 2:

FileA
FileB (Modified)
FileC
FolderA FileE
FolderA FolderB FileF

Is there any better solution?

有没有更好的解决办法?

采纳答案by Sotirios Delimanolis

A WatchServiceonly watches the Paths you register. It does not go through those paths recursively.

AWatchService只看Path你注册的s。它不会递归地通过这些路径。

Given /Rootas a registered path

鉴于/Root作为注册路径

/Root
    /Folder1
    /Folder2
        /Folder3

If there is a change in Folder3, it won't catch it.

如果 有变化Folder3,它就不会捕捉到它。

You can register the directory paths recursively yourself with

您可以自己递归注册目录路径

private void registerRecursive(final Path root) throws IOException {
    // register all subfolders
    Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
            dir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
            return FileVisitResult.CONTINUE;
        }
    });
}

Now the WatchServicewill notify all changes in all subfolders of Path root, ie. the Pathargument you pass.

现在WatchService将通知 的所有子文件夹中的所有更改Path root,即。Path你通过的论点。

回答by mjash

Registering recursively will work as Sotirios has indicated. This effectively registers each directory/sub-directory that currently exists.

递归注册将如 Sotirios 所指示的那样工作。这有效地注册了当前存在的每个目录/子目录。

You can alternatively import and use *com.sun.nio.file.ExtendedWatchEventModifier.FILE_TREE* as in:

您也可以导入和使用 *com.sun.nio.file.ExtendedWatchEventModifier.FILE_TREE*,如下所示:

dir.register(watcher, standardEventsArray, ExtendedWatchEventModifier.FILE_TREE);

This will watch the entire sub-tree for change AND account for added directories and sub-directories.

这将监视整个子树的更改和添加的目录和子目录的帐户。

Otherwise you will have to monitor for any new directories/sub-directories and register them also. There can also be an issue with deleting parts of the directory hierarchy since each registered directory has a handle watching it so the (lowest) sub-directories need to be removed first when deleting parts of the structure.

否则,您将必须监视任何新目录/子目录并同时注册它们。删除部分目录层次结构也可能存在问题,因为每个注册的目录都有一个监视它的句柄,因此在删除部分结构时需要首先删除(最低)子目录。

回答by Fabrizio Fortino

I have implemented something like this using Java 8 streams and lambdas.

我已经使用 Java 8 流和 lambdas 实现了这样的东西。

The recursive folder discovery is implemented as a Consumer@FunctionalInterface:

递归文件夹发现是作为消费者@FunctionalInterface 实现的:

    final Map<WatchKey, Path> keys = new HashMap<>();

    Consumer<Path> register = p -> {
        if (!p.toFile().exists() || !p.toFile().isDirectory()) {
            throw new RuntimeException("folder " + p + " does not exist or is not a directory");
        }
        try {
            Files.walkFileTree(p, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    LOG.info("registering " + dir + " in watcher service");
                    WatchKey watchKey = dir.register(watcher, new WatchEvent.Kind[]{ENTRY_CREATE}, SensitivityWatchEventModifier.HIGH);
                    keys.put(watchKey, dir);
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            throw new RuntimeException("Error registering path " + p);
        }
    };

The above code is called every time a new folder is created to dynamically add folders at later stages. Full solution and more details here.

每次创建新文件夹时都会调用上面的代码,以便在后期动态添加文件夹。完整的解决方案和更多细节在这里