我有一段代码监视目录以添加文件。每当将新文件添加到目录时,将挑选该文件的内容并在kafka上发布,然后删除该文件。
当我发出单个请求时,这是有效的,但是一旦我将代码从jMeter请求5或10个用户请求,内容就会在kafka上成功发布,但代码无法删除该文件。我收到FileSystemException
的消息The process cannot access the file because it is being used by another process.
。
我想有一些我无法看到的并发问题。
public void monitor() throws IOException, InterruptedException {
Path faxFolder = Paths.get(TEMP_FILE_LOCATION);
WatchService watchService = FileSystems.getDefault().newWatchService();
faxFolder.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
boolean valid = true;
do {
WatchKey watchKey = watchService.take();
for (WatchEvent<?> event : watchKey.pollEvents()) {
if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
String fileName = event.context().toString();
publishToKafka(new File(TEMP_FILE_LOCATION + fileName).toPath(), "topic");
}
}
valid = watchKey.reset();
} while (valid);
}
private void publishToKafka(Path path, String topic) {
try (BufferedReader reader = Files.newBufferedReader(path)) {
String input = null;
while ((input = reader.readLine()) != null) {
kafkaProducer.publishMessageOnTopic(input, topic);
}
} catch (IOException e) {
LOG.error("Could not read buffered file to send message on kafka.", e);
} finally {
try {
Files.deleteIfExists(path); // This is where I get the exception
} catch (IOException e) {
LOG.error("Problem in deleting the buffered file {}.", path.getFileName(), e);
}
}
}
异常日志:
java.nio.file.FileSystemException: D:\upload\notif-1479974962595.csv: The process cannot access the file because it is being used by another process.
at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsFileSystemProvider.implDelete(Unknown Source)
at sun.nio.fs.AbstractFileSystemProvider.deleteIfExists(Unknown Source)
at java.nio.file.Files.deleteIfExists(Unknown Source)
at com.panasonic.mdw.core.utils.MonitorDirectory$FileContentPublisher.publishToKafka(MonitorDirectory.java:193)
at com.panasonic.mdw.core.utils.MonitorDirectory$FileContentPublisher.sendData(MonitorDirectory.java:125)
at com.panasonic.mdw.core.utils.MonitorDirectory$FileContentPublisher.run(MonitorDirectory.java:113)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
答案 0 :(得分:2)
看看你的代码,似乎当一个文件被线程挑选再次发布时,另一个线程正在将其用于发布。这就是没有人能够删除它的原因。 它必须只是并发问题。您应该根据标准重新设计代码:可以同时运行的步骤和不可以运行的步骤。 因此,整个过程的步骤是:
此外,在选择文件的那一刻,您可以将其读入缓冲区,将其删除,然后继续发布。这将确保主线程不会将此文件分配给其他线程。
答案 1 :(得分:1)
在WatchService事件中添加睡眠时间总是一个更好的主意:
if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// now do your intended jobs ...
我需要添加睡眠时间,否则它不能用于多个请求并用来获取错误:
The process cannot access the file because it is being used by another process
答案 2 :(得分:0)
我遇到了类似问题以及以下主题:Multithreading on Queue 尝试将动态创建的文件上传到队列服务时,我需要2天才能解决。感谢Holger如上所述给出了答案,其中发生锁定可能是由于创建在另一个线程读取时没有完全完成,它为我节省了很多时间。
我从互联网上找到的最初解决方案是:
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
//queueUploadFile(child);
if (kind == ENTRY_CREATE) {
uploadToQueue(this.queueId, child);
}
我把它改为:
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
//queueUploadFile(child);
if (kind == ENTRY_MODIFY) {
uploadToQueue(this.queueId, child);
}
一切都很完美。为了处理“以某种方式”触发多个ENTRY_MODIFY事件(上传重复文件),我在上传后对uploadToQueue()方法内的文件执行删除。
我希望我基于上述贡献采取的方法也能帮助其他有类似问题的人。
答案 3 :(得分:-1)
在删除之前,您必须关闭正在访问该文件的所有连接。