【问题标题】:Java watch folder and action when all files and folders in watch folder have finished downloading监视文件夹中的所有文件和文件夹下载完成后的 Java 监视文件夹和操作
【发布时间】:2019-07-02 13:28:01
【问题描述】:

我正在尝试编写使用监视文件夹处理媒体文件的工具。 Oracle 示例WatchDir 演示了如何知道文件夹何时发生更改。但是,问题在于我不知道所有媒体何时完成上传。因此,例如,当包含包含不同文件夹中多个文件的媒体的 SD 卡被拖到监视文件夹中时,一旦所有文件和子文件夹都存在,我需要能够处理媒体。媒体并不总是只存储在单个文件中,还可能有附属文件,因此需要同时存在两组文件才能正确处理文件。谁能建议我如何知道所有文件和子文件夹都已完成复制到监视文件夹中?

这是我稍微修改的 WatchDir 版本,包括日志记录:

public class WatchDir {

    private final WatchService watcher;
    private final Map<WatchKey,Path> keys;
    private final boolean recursive;
    private boolean trace = false;

    @SuppressWarnings("unchecked")
    static <T> WatchEvent<T> cast(WatchEvent<?> event) {
        return (WatchEvent<T>)event;
    }

    /**
     * Register the given directory with the WatchService
     */
    private void register(Path dir) throws IOException {
        WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
        if (trace) {
            Path prev = keys.get(key);
            if (prev == null) {
                System.out.format("register: %s%n", dir);
            } else {
                if (!dir.equals(prev)) {
                    System.out.format("update: %s -> %s%n", prev, dir);
                }
            }
        }
        keys.put(key, dir);
    }

    /**
     * Register the given directory, and all its sub-directories, with the
     * WatchService.
     */
    private void registerAll(final Path start) throws IOException {
        // register directory and sub-directories
        Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                throws IOException
            {
                register(dir);
                return FileVisitResult.CONTINUE;
            }
        });
    }

    /**
     * Creates a WatchService and registers the given directory
     */
    WatchDir(Path dir, boolean recursive) throws IOException {
        this.watcher = FileSystems.getDefault().newWatchService();
        this.keys = new HashMap<WatchKey,Path>();
        this.recursive = recursive;

        if (recursive) {
            System.out.format("Scanning %s ...\n", dir);
            registerAll(dir);
            System.out.println("Done.");
        } else {
            register(dir);
        }

        // enable trace after initial registration
        this.trace = true;
    }

    /**
     * Process all events for keys queued to the watcher
     */
    void processEvents() {
        System.out.println("process event");
        boolean processing = false;
        for (;;) {
            System.out.println("loop");
            // wait for key to be signalled
            WatchKey key;
            try {
                processing = false;
                System.out.println("about to take");
                key = watcher.take();
                processing = true;

            } catch (InterruptedException x) {
                System.out.println("take interrupted");
                return;
            }

            Path dir = keys.get(key);
            if (dir == null) {
                System.err.println("WatchKey not recognized!!");
                continue;
            }

            for (WatchEvent<?> event: key.pollEvents()) {

                System.out.println("poll");
                WatchEvent.Kind kind = event.kind();

                // TBD - provide example of how OVERFLOW event is handled
                if (kind == OVERFLOW) {
                    System.out.println("Overflow");
                    continue;
                }

                // Context for directory entry event is the file name of entry
                WatchEvent<Path> ev = cast(event);
                Path name = ev.context();
                Path child = dir.resolve(name);

                // print out event
                System.out.format("%s: %s\n", event.kind().name(), child);

                // if directory is created, and watching recursively, then
                // register it and its sub-directories
                if (recursive && (kind == ENTRY_CREATE)) {
                    try {
                        if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
                            registerAll(child);
                        }
                    } catch (IOException x) {
                        // ignore to keep sample readable
                        System.out.println("ex: " + x.getMessage());
                    }
                }
            }

            // reset key and remove from set if directory no longer accessible
            boolean valid = key.reset();
            if (!valid) {
                keys.remove(key);
                System.out.println("finished this set of files");
                // all directories are inaccessible
                if (keys.isEmpty()) {
                    break;
                }
            }
            if (processing) {
                System.out.println("processing files...");
            } else {
                System.out.println("not processing files");
            }
            System.out.println("End of loop\n\n");
        }
    }

    static void usage() {
        System.err.println("usage: java WatchDir [-r] dir");
        System.exit(-1);
    }

    public static void main(String[] args) throws IOException {
        // parse arguments
        if (args.length == 0 || args.length > 2)
            usage();
        boolean recursive = false;
        int dirArg = 0;
        if (args[0].equals("-r")) {
            if (args.length < 2)
                usage();
            recursive = true;
            dirArg++;
        }

        // register directory and process its events
        Path dir = Paths.get(args[dirArg]);
        new WatchDir(dir, recursive).processEvents();
    }
}

【问题讨论】:

    标签: java watch


    【解决方案1】:

    也许你不能那样做。根据docWatchService 只提供了这些事件:

    static WatchEvent.Kind<Path>  ENTRY_DELETE Directory entry deleted.
    static WatchEvent.Kind<Path>  ENTRY_MODIFY Directory entry modified.
    static WatchEvent.Kind<Object>    OVERFLOW A special event to indicate that events may have been lost or discarded. ```
    

    所以你不会知道是否有新文件要创建/复制到你的目录。

    也许您可以考虑一些解决方法:

    • 设置一个超时时间,如果没有创建新文件,则认为文件传输完成并开始工作。
    • 让您的应用程序来处理复制,以便在复制所有文件后知道进度并触发工作。

    【讨论】:

    • 感谢@TKJohn 的建议。我可以判断单个文件何时完成上传,但问题是我正在使用的媒体通常由多个文件组成,例如,可能有一个包含与媒体文件关联的元数据的边车文件。所以我不能处理单个文件。关于您的第二个建议,复制可以通过其他 3 个应用程序进行,因此我无法控制复制过程。
    • 我个人会选择超时方法(因为如果它是一个桌面应用程序,那么用户通过你的应用程序进行复制文件这样简单的事情是一个正确的痛苦,除非你的应用程序是文件管理器)。 @karen,您不必为单个文件工作。一般的想法是在您的应用程序中设置一个计数器,例如每秒计数一次,并侦听ENTRY_CREATEENTRY_MODIFY 事件 - 如果有一段时间都没有发生,则认为复制已完成,您可以开始处理.我认为,您需要自己查看多少“一段时间”,因为这取决于文件大小。
    猜你喜欢
    • 2022-01-01
    • 2012-02-22
    • 2012-10-05
    • 2019-03-09
    • 2016-12-24
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多