正在批处理应用程序中从Files.move获取java.nio.file.NoSuchFileException

正在批处理应用程序中从Files.move获取java.nio.file.NoSuchFileException,java,nio,nosuchfileexception,Java,Nio,Nosuchfileexception,背景 这是一个多线程批处理应用程序,每个线程都有自己的文件。我在别处有一个逻辑,它可以在文件创建失败的情况下阻止文件重命名 这个进程作为守护进程运行,每天生成几千个文件。这种异常可能每3天发生一个文件,因此我们使用的方法大部分时间都有效 运行批处理的机器是Red Hat Enterprise Linux Server 6.7版(圣地亚哥) Java版本是1.8.0_162 临时文件名是通过将java.util.UUID中的UUID.randomUUID()的结果追加而生成的 实际文件名可能有重复

背景

这是一个多线程批处理应用程序,每个线程都有自己的文件。我在别处有一个逻辑,它可以在文件创建失败的情况下阻止文件重命名

这个进程作为守护进程运行,每天生成几千个文件。这种异常可能每3天发生一个文件,因此我们使用的方法大部分时间都有效

运行批处理的机器是Red Hat Enterprise Linux Server 6.7版(圣地亚哥)

Java版本是1.8.0_162

临时文件名是通过将java.util.UUID中的UUID.randomUUID()的结果追加而生成的

实际文件名可能有重复项,这就是为什么我们使用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;
}
我唯一能想到的解决办法就是让线程休眠几毫秒,以防它是文件系统级的问题。问题是,在非prod环境中复制异常非常困难

我怀疑,当几乎所有线程都具有相同的真实文件名时,会发生异常,因此会有大量重命名为相同的文件名,但我不能确定这一点

谢谢

**编辑:**


我们有一个正在运行的skybot作业,它用一个。超过一天的csv扩展。我认为作业在查找要移动的文件时锁定了文件夹中的所有文件。在我做了一个代码修复,允许我删除skybot作业后,问题就消失了

文件之前。移动
运行
文件。创建目录
如示例所示:

Files.createDirectories(Paths.get("pathTo"));
Files.move(Paths.get("pathFrom"), Paths.get("pathTo"));