WatchService. WatchEvent .context() метод возвращает непоследовательный относительный путь для файла в ENTRY_MODIFY (goutputstream-####, ОС Linux)

В этом коде я надеюсь обновить HashMap самой последней версией содержимого заданного пути, указав в качестве ключа абсолютный путь в виде строки. Проблема в том, что WatchEvent"s .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 в просматриваемой директории от содержимого "abc" до "abc 123"

Обратите внимание, что все это происходит просто путем открытия файла /workspaces/b.txt (который уже существует) и изменения его содержимого.):

    бежать:
    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") для этого файла?

Кажется, что когда я выполняю модификацию, я получаю последовательность событий создания / изменения / создания, и ENTRY_CREATEс правильным именем файла, ENTRY_MODIFYу меня есть временный дескриптор (я предполагаю, что временная версия файла используется между сохранениями). Мне нужно иметь возможность зафиксировать изменение файла и извлечь правильное имя файла из этого события.

Я понимаю, что моя файловая система может выполнять создание и обработку временного файла под капотом, пока я просто открываю, изменяю и сохраняю файл, но как именно я могу извлечь правильное имя файла из временного файла, который указывает событие ENTRY_MODIFY дает мне? Есть ли какой-то метод для группировки событий, относящихся к этой модификации, чтобы я мог просто найти вмещающий ENTRY_CREATE и получить имя файла от этого? Или как-то пройти вверх через стек вызовов, ведущих к этому ENTRY_CREATE?

Я могу увидеть имя файла во вложении ENTRY_CREATE события, окружающие друг ENTRY_MODIFY, но я надеюсь, что есть более элегантный способ сделать это, чем каким-либо образом (получить последнее событие, которое не было ENTRY_MODIFY, а затем получить .context() От этого.)

Спасибо!

1 ответ

Решение

Я столкнулся с тем же вопросом. Я думаю, что это не имеет никакого отношения к проблемам Linux или Java. Это просто способ, которым редактор b.txt (я полагаю, gedit) обрабатывает эту вещь.

После сохранения

  1. создает новый временный файл ".goutputstream-xxxx" с каким-то случайным xxxx (который вы видите),

  2. записывает новое содержимое в этот файл (видоизменяемое вами изменение),

  3. переименовывает исходный файл в b.txt~ (то, что вы видите),

  4. и переименовывает временный файл в b.txt (создание, которое вы видите)

Поэтому я думаю, что вам нужно следить за ENTRY_MODIFY и ENTRY_CREATE в отношении b.txt, чтобы действительно увидеть все модификации файла.

У меня такая же проблема. Я использую фильтр, чтобы исключить эту проблему. Например: мне нужны все файлы в пути /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());

Это исправление для меня.

Другие вопросы по тегам