filenotfoundexception—在java的监视服务期间,即使文件在适当的位置,filenotfoundexception也会发生异常

gwo2fgha  于 2021-07-11  发布在  Java
关注(0)|答案(3)|浏览(392)

我在一个文件夹上运行了一个监视服务,当我试图使用evenkind==modify修改现有文件时(基本上粘贴同一个文件而不删除当前文件),我得到了filenotfoundexception(进程无法访问该文件,因为它正被另一个进程使用)

if (eventKind == StandardWatchEventKinds.ENTRY_MODIFY) {

                String newFileChecksum = null;

                if (eventPath.toFile().exists()) {
                    newFileChecksum = getFileChecksum(eventPath.toFile());

                }

                if (fileMapper.containsKey(eventPath)) {
                    String existingFileChecksum = fileMapper.get(eventPath);

                if (!existingFileChecksum.equals(newFileChecksum)) {

                        fileMapper.replace(eventPath, existingFileChecksum, newFileChecksum);

                        log.info("listener.filemodified IN");
                        for (DirectoryListener listener : this.listeners) {

                            listener.fileModified(this, eventPath);
                        }
                        log.info("listener.filemodified OUT");
                    } else {
                        log.info("existing checksum");
                        log.debug(String.format(
                                "Checksum for file [%s] has not changed. Skipping plugin processing.",
                                eventPath.getFileName()));
                    }

                }

            }

在调用…getfilechecksum()时的代码中

if (eventPath.toFile().exists()) {

        newFileChecksum = getFileChecksum(eventPath.toFile());

}

所以,理想情况下,eventpath.tofile().exists()为true,所以如果调用getfilechecksum()时,代码将进入方法。。。

private synchronized String getFileChecksum(File file) throws IOException, NoSuchAlgorithmException {

        MessageDigest md5Digest = MessageDigest.getInstance("MD5");

        FileInputStream fis = null;

        if(file.exists()) {

            try {
                fis = new FileInputStream(file);
            } catch(Exception e) {
                e.printStackTrace();
            }
        } else {
            log.warn("File not detected.");
        }

        byte[] byteArray = new byte[1024];

        int bytesCount = 0; 

        while ((bytesCount = fis.read(byteArray)) != -1) {

            md5Digest.update(byteArray, 0, bytesCount);
        };

        fis.close();

        byte[] bytes = md5Digest.digest();

        StringBuilder stringBuilder = new StringBuilder();

        for (int i=0; i< bytes.length ;i++) {

            stringBuilder.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
        }

       return stringBuilder.toString();
    }
}

出现异常fis=newfileinputstream(文件);即使文件夹中存在该文件。
filenotfoundexception(进程无法访问该文件,因为另一个进程正在使用它。)
我创建了一个randomaccessfile和一个通道来释放文件上的任何锁,但它不起作用。请告诉我这里会发生什么。
//更新-->这是我的无限while循环,
发生了什么事?当我放置一个文件时,调用1 create和2 update,假设,当我删除该文件时,调用1 delete和1 modify,如果我将同一个文件放回文件夹,则调用create,但在create完成之前,调用modify。而create没有运行,而modify正在运行。
我将thread.sleep(500)放在

WatchKey wk = watchService.take();
Thread.sleep(500)
        for (WatchEvent<?> event : wk.pollEvents()) {

但我不认为我有理由在这里睡觉。请帮忙
watchservice watchservice=null;watchkey watchkey=null;

while (!this.canceled && (watchKey == null)) {

           watchService = watchService == null
                        ? FileSystems.getDefault().newWatchService() : watchService;
                watchKey = this.directory.register(watchService,
                        StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE,
                        StandardWatchEventKinds.ENTRY_CREATE);
         }
         while (!this.canceled) {

    try {

        WatchKey wk = watchService.take();

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

            Kind<?> eventKind = event.kind();

            System.out.println("Event kind : " + eventKind);

            Path dir = (Path)wk.watchable();
            Path eventPath = (Path) event.context();

            Path fullPath = dir.resolve(eventPath);
            fireEvent(eventKind, fullPath);
        }

        wk.reset();

    }
kxeu7u2r

kxeu7u2r1#

我有一个更好的方法,在var isfileready上使用while循环,就像这样。。。

var isFileReady = false;

while(!isFile...) {
}

在里面,同时创造一个尝试和捕捉。

try {

FileInputStream fis = new FileInputStream();

isFileReady = true;
} catch () {
catch exception or print file not ready.
}

这会解决你的问题。

zyfwsgd6

zyfwsgd62#

watchservice非常冗长,可能会报告多个条目的\u修改事件以执行保存操作—即使另一个应用程序正在执行部分操作或重复执行写入操作。当另一个应用程序仍在编写时,您的代码可能正在对修改事件执行操作,并且可能有第二个条目正在进行修改。
使用watchservice的一个更安全的策略是整理接收到的事件,并且只在暂停时对更改采取行动。类似这样的操作将确保您在第一个事件上阻塞,但在对上一个事件集执行操作之前,会以较小的超时轮询监视服务,以查看是否存在更多更改:

WatchService ws = ...
HashSet<Path> modified = new HashSet<>();

while(appIsRunning) {
    int countNow = modified.size();
    WatchKey k = countNow == 0 ? ws.take() : ws.poll(1, TimeUnit.MILLISECONDS);
    if (k != null) {
        // Loop through k.pollEvents() and put modify file path into modified set:
        // DO NOT CALL fireEvent HERE, save the path instead:
        ...
        if (eventKind == ENTRY_MODIFY)
            modified.add(filePath);
    }
    // Don't act on changes unless no new events:
    if (countNow == modified.size()) {
        // ACT ON modified list here - the watch service did not report new changes
        for (Path filePath : modified) {
           // call fireEvent HERE:
           fireEvent(filePath);
        }

        // reset the list so next watch call is take() not poll(1)
        modified.clear();
    }
}

如果还希望使用modify执行create和delete操作,则必须整理并忽略一些早期事件,因为最后记录的事件类型可能优先于先前记录的类型。例如,如果调用take(),则轮询(1),直到没有新的报告:
任何delete-then-create=>您可能需要将其视为modify
任何create-then-modify=>您可能希望将其视为create
任何创建或修改,然后删除=>视为删除
你的逻辑也只想在 modified.size() + created.size() + deleted.size() 在两次运行之间更改。

kadbb459

kadbb4593#

让我猜猜。。。
修改文件时调用modify事件。要修改文件,您最有可能使用一个单独的工具,如记事本,打开并锁定文件。
你的观察者得到一个事件,文件被修改了(现在),但是你不能再修改它(fileinputstream想要这样做),因为它已经被锁定了。

相关问题