【问题标题】:Java NIO watch Service created both 'ENTRY_CREATE' and 'ENTRY_MODIFY' when a new File is added to the watch folder将新文件添加到监视文件夹时,Java NIO 监视服务创建了“ENTRY_CREATE”和“ENTRY_MODIFY”
【发布时间】:2023-05-12 16:34:02
【问题描述】:

我看到一个使用 java.nio.file.WatchService 的奇怪行为(不确定这是预期行为)。

问题是我有一个使用 WatchService 注册的文件夹。 当我将一个新文件复制到此文件夹中时,会生成两个 WatchEvent,每个用于:

'ENTRY_CREATE' 和“ENTRY_MODIFY”。

据我了解,一个新文件(从没有被监视的其他目录复制)必须只创建一个事件,即:'ENTRY_CREATE'。

谁能解释为什么会创建额外的事件“ENTRY_MODIFY”?

我的代码:

public void watch() {
    WatchKey key = watcher.poll();

    //log.info("Watcher scheduler running. Watch key {}", key.hashCode());

    if (key != null) {
        Workflow workflow = keys.get(key);
        log.info("Runing watcher for key '{}'  and workflow {}", key.hashCode(), workflow.getName());
        File hotFolder = new File(workflow.getFolderPath());
        Path dir = hotFolder.toPath();

        for (WatchEvent<?> event : key.pollEvents()) {
            WatchEvent<Path> ev = cast(event);
            Path name = ev.context();
            Path child = dir.resolve(name);

            log.info("Polling event for name {} and child {} and dir {}", name.toFile(), child.toFile(), dir.toFile());

            if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS))
                continue;

            try {
                switch (event.kind().name()) {
                case "ENTRY_CREATE":
                    log.info("New file {}", child.toFile());
                    fileService.processNewFile(child.toFile(), workflow);
                    break;
                case "ENTRY_MODIFY":
                    log.info("File modified.... {}", child.toFile());
                    fileService.processModifiedFile(child.toFile(),
                            workflow);
                    break;
                default:
                    log.error("Unknown event {} for file {}", event.kind()
                            .name(), child.toFile());
                    break;
                }
                // Operation op = Operation.from(event.kind());
                // if (op != null)
                // publisher.publishEvent(new FileEvent(child.toFile(),
                // workflow, op));
            } catch (Throwable t) {
                log.warn("Error while procesing file event", t);
            }
        }

        key.reset();
    }
}

所以当我复制一个文件时,比如 name = "abc.txt",日志显示:
新文件 abc.txt
文件已修改.... abc.txt


强烈要求提供任何意见。

【问题讨论】:

    标签: java nio watchservice


    【解决方案1】:

    检查WatchService JavaDoc 中的“平台依赖项”部分。

    Watcher 在您描述的情况下表现正确。严格来说,当您将文件复制到文件夹时,文件实际上是先创建后修改的。

    在使用 WatcherService 时需要考虑很多事情,它的行为变化很大,例如:

    • 操作系统
    • 加密光盘
    • 网络共享
    • ...

    【讨论】:

      【解决方案2】:

      我想,这里已经回答了这个问题。

      例如Java: WatchService gets informed before content is copied

      简而言之,事件是由您的操作系统生成的。您有两个事件,这意味着您的操作系统以非原子方式执行复制。如果您尝试读取介于 ENTRY_CREATE 和 ENTRY_MODIFY 之间的文件,它将不一致。但同样,这取决于您的操作系统。例如,在 Windows 7 上,对于大文件,我将获得 ENTRY_CREATE 一次和 ENTRY_MODIFY 两次。 所以你实际上不能确定文件是否被成功复制,你必须想出依赖于应用程序/操作系统的指标。

      【讨论】: