java - 如何确保监视目录中通过SFTP上传的所有文件都可以通过Java7使用?

标签 java continuous-integration java-7 sftp

我正在使用 WatchService 来监视目录。另一个第三方将通过 SFTP 将大型 CSV 文件上传到该目录。我必须等到所有文件都完成才能开始处理文件。

我现在的麻烦是,SFTP 在上传开始后立即创建文件,我得到 ENTRY_CREATE 并不断得到 ENTRY_MODIFY 直到文件完成。无论如何,有没有办法判断文件是否真正完成。

这是我使用的代码,是从 Java 文档中获取的

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() {
    for (; ; ) {

        // wait for key to be signalled
        WatchKey key;
        try {
            key = watcher.take();
        } catch (InterruptedException x) {
            return;
        }

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

        for (WatchEvent<?> event : key.pollEvents()) {
            WatchEvent.Kind kind = event.kind();

            // TBD - provide example of how OVERFLOW event is handled
            if (kind == 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 readbale
                }
            }
        }

        // reset key and remove from set if directory no longer accessible
        boolean valid = key.reset();
        if (!valid) {
            keys.remove(key);

            // all directories are inaccessible
            if (keys.isEmpty()) {
                break;
            }
        }
    }
}

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();
}

}

最佳答案

在Linux下,您可以使用“inotify”工具。他们可能带着所有主要的物资抵达。这是它的维基:wiki - Inotify

请注意您所支持的事件列表:

IN_CLOSE_WRITE - sent when a file opened for writing is closed

IN_CLOSE_NOWRITE - sent when a file opened not for writing is closed

这些就是您要寻找的。我没能在 Windows 上看到类似的东西。 至于使用它们,可以有多种方式。我使用了一个java库jnotify

请注意,该库是跨平台的,因此您不想使用主类,因为 Windows 不支持关闭文件的事件。您将需要使用 linux API,它公开了完整的 linux 功能。只需阅读描述页面,您就知道它是您所要求的:jnotify - linux

请注意,就我而言,我必须下载库源代码,因为我需要编译 64 位共享对象文件“libjnotify.so”。提供的只能在 32 位下运行。也许他们现在就提供了,你可以检查一下。

查看代码示例以及如何添加和删除 watch 。例如,只需记住使用“JNotify_linux”类而不是“JNotify”,然后您就可以在操作中使用掩码。

私有(private)最终 int MASK = JNotify_linux.IN_CLOSE_WRITE;

希望它对您有用。

关于java - 如何确保监视目录中通过SFTP上传的所有文件都可以通过Java7使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20631045/

相关文章:

java - 使java代码适应所使用的jdk版本

java - 涉及 Document 和 DocumentBuilder 的 JUnit 测试时验证错误

java.sql.SQLException : Unknown initial character set index '255' received from server for connector 8. 0.11

docker - 构建器的 Gitlab CI 拉取访问被拒绝,存储库不存在或可能需要 'docker login'

unit-testing - Chrome Webdriver 在 headless 模式下丢失用户凭据

c# - 通过 TFS/Team Build 在构建机器上构建工作,但不通过 TeamCity

java - 如何在 google-service.json 中添加 Signed Apk Keystone

java - 使用 Netbeans IDE 在 jTree Java 上获取字符串值

java - 如何正确处理连接空闲超时错误

java - 新的dll "sunec.dll"文件和JAVA7有什么用