Получение java.nio.file.NoSuchFileException из Files.move в пакетном приложении
Фон
Это многопоточное пакетное приложение, каждый поток имеет свой собственный файл. У меня есть логика в другом месте, которая остановит переименование файла в случае сбоя создания файла.
Этот процесс запускается как демон и генерирует несколько тысяч файлов каждый день. Это исключение происходит, возможно, для одного файла за 3 дня, поэтому используемый нами метод работает большую часть времени.
Машина, на которой выполняется партия, Red Hat Enterprise Linux Server release 6.7 (Santiago)
Java версия 1.8.0_162
Имена временных файлов создаются путем добавления результата UUID.randomUUID() из java.util.UUID.
Реальное имя файла может иметь дубликаты, поэтому мы использовали rand UUID вместо.tmp для имени временного файла. Это не должно быть проблемой, так как часть перемещения находится в синхронизированном блоке.
Исключение:
2018-07-26 15:06:01,743 ERROR (ProcessRecordsTask.java:renameFileAfterProcess():674) - Error: Unable to rename file:
java.nio.file.NoSuchFileException: /logs/apps/appname/FILNAMESTUFF_07_26_2018_15_05_51.xml.5c80331c-3b7e-4e16-90d7-c0d7810451c5 -> /logs/apps/appname/FILNAMESTUFF_07_26_2018_15_05_51.xml
at sun.nio.fs.UnixException.translateToIOException(UnixException.java:86)
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
at sun.nio.fs.UnixCopyFile.move(UnixCopyFile.java:396)
at sun.nio.fs.UnixFileSystemProvider.move(UnixFileSystemProvider.java:262)
at java.nio.file.Files.move(Files.java:1395)
at com.filetransferbatch.task.ProcessRecordsTask.renameFileAfterProcess(ProcessRecordsTask.java:664)
at com.filetransferbatch.task.ProcessRecordsTask.saveFileData(ProcessRecordsTask.java:349)
at com.filetransferbatch.task.ProcessRecordsTask.xmlTransfer(ProcessRecordsTask.java:244)
at com.filetransferbatch.task.ProcessRecordsTask.call(ProcessRecordsTask.java:162)
at com.filetransferbatch.task.ProcessRecordsTask.call(ProcessRecordsTask.java:62)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Я получаю исключение из следующего фрагмента:
private boolean renameFileAfterProcess(String tmpFileName) {
boolean fileRenamed = false;
try {
if (null != tmpFileName && (!("".equals(tmpFileName)))) {
Path tmpFilePath = Paths.get(tmpFileName);
logger.info("tmpFilePath:" + tmpFilePath + ":Renamed Filepath: " + realFilePath);
Path realFile = Paths.get(realFilePath);
synchronized (this) {
logger.info("File " + tmpFilePath + " exists: " + Files.exists(tmpFilePath));
Files.move( tmpFilePath,
realFile,
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.ATOMIC_MOVE);
logger.info(tmpFileName + ":File was successfully renamed to :" + realFilePath);
fileRenamed = true;
}
}
} catch (IOException e) {
fileRenamed = false;
logger.error("Error: Unable to rename file:", e);
} catch (Exception e) {
logger.error("Error :", e);
}
return fileRenamed;
}
Файл создан таким образом
private boolean createFile(String fileName, byte[] fileDataMerged) {
boolean fileCreated = false;
if (fileName.trim().length() != 0) {
try {
Path createdFilePath = Files.write( Paths.get(tmpFilePath),
fileDataMerged,
StandardOpenOption.SYNC,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE);
if (createdFilePath != null) {
fileCreated = Files.exists(createdFilePath);
}
} catch (IOException e) {
logger.error("Error writing temp file: ", e);
} catch (Exception e) {
logger.error("Error writing temp file: ", e);
}
}
return fileCreated;
}
Единственное, что я могу придумать, чтобы это исправить, это, возможно, приостановить поток на несколько миллисекунд, если это проблема уровня файловой системы. Проблема в том, что действительно трудно воспроизвести исключение в среде, не являющейся продуктом.
У меня есть подозрение, что исключение происходит, когда почти все потоки имеют одно и то же реальное имя файла, поэтому существует множество переименований в одно и то же имя файла, но я не уверен в этом.
Спасибо
0 ответов
До
Files.move
бежать
Files.createDirectories
как в примере:
Files.createDirectories(Paths.get("pathTo"));
Files.move(Paths.get("pathFrom"), Paths.get("pathTo"));