Java8 使用 Files.list (),遇到的坑(未关闭流)

公司业务在与第三方业务进行文件交互时,有读取目录下所有文件的操作,采用的是Files.list()方法读取。
程序跑了几天后,报出 java.nio.file.FileSystemException: /data/xml/product/xml_2438.xml: Too many open files 异常。
经过排查,服务器上句柄数设置为了 60000,与没有上限无异了,确认应当是程序的问题。
经过排查和在测试环境测试,使用 lsof -p 检查打开的文件句柄时可以看到的打开文件句柄列表变得越来越长,原因是使用 Files.list() 方法打开文件后未明确的关闭流,将会消耗大量的系统资源,使用 try-with-resources 关闭流,有相同问题的还有 Files.lines 方法,最终修改代码为:

        // 删除bad文件下的车牌图
        try (Stream<Path> list = Files.list(Paths.get(badFilesPath))) {
            List<Path> badFiles = list.filter(path -> !Files.isDirectory(path) && path.getFileName().toString().endsWith(".jpg"))
                    .collect(Collectors.toList());
            if (!badFiles.isEmpty()) {
                for (Path badFile : badFiles) {
                    Files.delete(badFile);
                }
            }
            badFiles.clear();
        }

如果关闭Stream,Files.list()确实会关闭其用于流式传输文件的底层DirectoryStream,因此只要关闭Stream,就不会有资源泄漏。
要了解的关键是,使用关闭流本身时会调用的Runnable向流中注册Stream::onClose。该Runnable是通过工厂方法asUncheckedRunnable创建的,该方法创建一个Runnable来关闭传递给它的资源,并将在IOException期间引发的所有close()转换为UncheckedIOException

你可能感兴趣的:(java,intellij-idea,spring,boot)