0

In java, when I add or change or delete any file, I hope the program execute the same action in another directory.It means, if I add a file "test.txt" in E://aaa, the program should copy "test.txt" from E://aaa to D://bbb。

I use java.nio.file.WatchService to implement it, but I can not get files' real path in program, Here is my code:

public void watchPath(Path watchPath, Path targetPath) throws IOException, InterruptedException {
    try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
        watchPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY,
                StandardWatchEventKinds.ENTRY_DELETE);
        while (true) {
            final WatchKey key = watchService.take();
            for (WatchEvent<?> watchEvent : key.pollEvents()) {
                final Kind<?> kind = watchEvent.kind();
                if (kind == StandardWatchEventKinds.OVERFLOW) {
                    continue;
                }
                final WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent;
                Path systemFileDir = (Path) key.watchable(); // TODO Here can not get the real path
                //System.out.println(systemFileDir.toString()); // E:/aaa
                //System.out.println(systemFileDir.toAbsolutePath()); // E:/aaa
                //System.out.println(systemFileDir.toRealPath()); // E:/aaa
                final Path path = watchEventPath.context();
                String fileAbsPath = systemFileDir + File.separator + path;
                Path original = Paths.get(fileAbsPath);
                String targetAbsPath = fileAbsPath.replace(watchPath.toString(), targetPath.toString());
                Path target = Paths.get(targetAbsPath);
                File file = new File(targetAbsPath);
                if (kind == StandardWatchEventKinds.ENTRY_CREATE || kind == StandardWatchEventKinds.ENTRY_MODIFY) {
                    if (file.isDirectory() && !file.exists()) { // 如果是目录
                        file.mkdirs();
                    } else {
                        Files.copy(original, target, StandardCopyOption.REPLACE_EXISTING);
                    }
                }
                if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
                    Files.delete(target);
                }
            }
            boolean valid = key.reset();
            if (!valid) {
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Now the question is, when I add a file or directory in E://aaa/x, the program can not get the real path. For example, I added the file E://aaa/x/test.txt, I hope I can get this absolute path then copy it to destination, but I just get the RootPath E://aaa。

How Can I solve it ? Thx!

Leon
  • 331
  • 2
  • 3
  • 14

1 Answers1

0

Based on your comment:

The reason you have the problem is because you only ever register the parent folder. If you want to get an exact path for edits made in a sub folder then you need to register your watcher in those sub folders as well. One way to do this is to walk through the entire file tree right at the start and register everything.

Here is a perfect example:

http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java

Now you just need to modify that code snippet to suite your needs by adjusting the processEvents() method to check the event type then use the child variable to do the same action in your other folder.

Here is a crude example of an edit you could make to processEvents to go about adding folders in your mirrored directory:

    Path child = dir.resolve(name);
    if (kind == StandardWatchEventKinds.ENTRY_CREATE && (check if directory here))
    {
        String destinationToMirror = "D" + child.toString().substring(1);
        File file = new File(destinationToMirror);
        file.mkdir();
    }

Else read up on walking the file tree so you can just add the necessary bits to your own code: http://docs.oracle.com/javase/tutorial/essential/io/walk.html


Original Answer:

Try something like this:

Path original = systemFileDir.resolve(watchEventPath.context());

Instead of:

final Path path = watchEventPath.context();
String fileAbsPath = systemFileDir + File.separator + path;
Path original = Paths.get(fileAbsPath);

Note the main difference being how the path is resolved using dir.resolve

Credit: java.nio.file.WatchEvent gives me only relative path. How can I get the absolute path of the modified file?

Community
  • 1
  • 1
sorifiend
  • 5,927
  • 1
  • 28
  • 45
  • If I add a folder in E:\\aaa\x, I want to get the path "E:\\aaa\x\y", but `systemFileDir.resolve(watchEventPath.context())` just return "E:\\aaa\x", and I do not know how to get my new folder name "y"。 – Leon Sep 26 '16 at 06:05
  • @JasonGan See my edits. But in essence: http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java – sorifiend Sep 26 '16 at 06:51