观察服务 WatchService 的 WatchEvent.context() 方法在 ENTRY_MODIFY(goutputstream-####,Linux 操作系统)的文件上返回不一致的相对路径。

4
在这段代码中,我希望使用绝对路径作为键来更新HashMap中给定路径内容的最新版本。问题在于WatchEvent.context()方法在每个事件中为同一文件提供了不同的相对路径。
以下是代码片段:
            else if(event.kind()==StandardWatchEventKinds.ENTRY_MODIFY)
            {
                /*Variable path is a Path of "//workspaces", set earlier.*/
                Path oldfilepath=path.resolve((Path)event.context()); /*problem line*/
                String oldfilepathstring = oldfilepath.toString();
                 FileReader oldIn = new FileReader(oldfilepathstring);
                 BufferedReader br = new BufferedReader(oldIn);
                 String line;
                 List<String> newfiletext=new LinkedList<>();
                  while((line = br.readLine())!=null)
                    newfiletext.add(line);

                 List<String> previousText=new LinkedList<>();
                 if((previousText = fileMappings.get(oldfilepathstring))!= null)
                 {
                      System.out.println("previoustext:\n"+previousText);
                      System.out.println("newfiletext:\n"+newfiletext);
                 }

                 fileMappings.put(oldfilepathstring, newfiletext);
                 System.out.println(fileMappings.keySet()+"\n"+fileMappings.values());
            }

        }

以下是对修改文件b.txt的监控,并在监控目录中修改其内容时生成的样本输出:

请注意,所有这些都来自于打开已存在的文件 /workspaces/b.txt 并修改其内容。

    run:
    ENTRY_CREATE:.goutputstream-BRC1HX
    ENTRY_MODIFY:.goutputstream-BRC1HX
    [/workspaces/.goutputstream-BRC1HX]
    [[]]
    ENTRY_MODIFY:.goutputstream-BRC1HX
    previoustext:
    []
    newfiletext:
    [abc]
    [/workspaces/.goutputstream-BRC1HX]
    [[abc]]
    ENTRY_CREATE:b.txt~
    ENTRY_CREATE:b.txt
    ENTRY_CREATE:.goutputstream-MFJ6HX
    ENTRY_MODIFY:.goutputstream-MFJ6HX
    [/workspaces/.goutputstream-MFJ6HX, /workspaces/.goutputstream-BRC1HX]
    [[], [abc]]
    ENTRY_MODIFY:.goutputstream-MFJ6HX
    previoustext:
    []
    newfiletext:
    [abc, 123]
    [/workspaces/.goutputstream-MFJ6HX, /workspaces/.goutputstream-BRC1HX]
    [[abc, 123], [abc]]
    ENTRY_CREATE:b.txt~
    ENTRY_CREATE:b.txt

代码中的关键语句为 Path oldfilepath=path.resolve((Path)event.context());

oldfilepath 的解析结果是 "/workspaces/.goutputstream-MFJ6HX",之后是同一个文件的 "/workspaces/.goutputstream-BRC1HX"。

每次修改后,event.context() 都会返回同一个文件的不同路径。这是 Linux 还是 Java 的问题?我该如何精确地获取相对路径(即 "b.txt")?

看起来当我执行修改操作时,我得到了一系列的 create/modify/create 事件,而 ENTRY_CREATE 具有正确的文件名,而 ENTRY_MODIFY 具有一个临时句柄(我猜测是保存之间使用的临时文件版本)。我需要能够捕获文件修改并从该事件中提取正确的文件名。

我知道在我打开、修改和保存文件时,我的文件系统可能会在幕后进行临时文件的创建和处理,但我应该如何从表示 ENTRY_MODIFY 的事件中提取正确的文件名呢?是否有一种方法可以分组与此修改相关的事件,以便我只需找到封闭的 ENTRY_CREATE 并从其获取文件名?或者通过遍历调用堆栈向上遍历到该 ENTRY_CREATE

我能看到在每个ENTRY_MODIFY周围的封闭ENTRY_CREATE事件中的文件名,但我希望有一种更加优雅的方法来做这件事,而不是通过某种方式(获取最近的不是ENTRY_MODIFY的事件,然后从中获取.context())。
谢谢!
2个回答

6
我遇到了相同的问题。我认为这与任何Linux问题或任何Java问题无关,只是b.txt编辑器(我假设是gedit)的处理方式。
保存时,
1.创建一个名为“.goutputstream-xxxx”的新临时文件,其中xxxx是一些随机数(您看到的“create”), 2.将新内容写入此文件(您看到的“modify”), 3.将原始文件重命名为b.txt〜(您看到的“create”), 4.将临时文件重命名为b.txt(您看到的“create”)
因此,我想您必须注意b.txt的ENTRY_MODIFY和ENTRY_CREATE,以真正查看所有文件修改。

谢谢。让我感到惊讶的是,Java创建了一个依赖于系统默认文本编辑器的库。我认为跨系统可移植性的问题应该排除这样的功能。 - Mer

0

我有同样的问题。我使用筛选器来排除这个问题。 例如:我需要路径/home/user/data/in中的所有文件;

Files.walk(Paths.get( System.getProperty("user.home").concat("/data/in")))
                    .map(Path::toString)
                    .filter(path -> ! path.endsWith("/in"))
                    .filter(path -> ! path.startsWith(".goutputstream"))
                    .collect(Collectors.toList());

这个对我有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接