Java 获取太多打开的文件时出错,即使在使用了try with resources之后也是如此
我们在tomcat 7上部署了一个应用程序,该应用程序生成csv文件,并在成功将其上传到目标系统后将其移动到存档文件夹 我已经编写了一个spring作业,用于清理早于阈值天数的文件 我们收到太多打开的文件错误,如下所示Java 获取太多打开的文件时出错,即使在使用了try with resources之后也是如此,java,ioexception,Java,Ioexception,我们在tomcat 7上部署了一个应用程序,该应用程序生成csv文件,并在成功将其上传到目标系统后将其移动到存档文件夹 我已经编写了一个spring作业,用于清理早于阈值天数的文件 我们收到太多打开的文件错误,如下所示 java.nio.file.FileSystemException: /app/CSVArchive: Too many open files at sun.nio.fs.UnixException.translateToIOException(UnixException
java.nio.file.FileSystemException: /app/CSVArchive: Too many open files
at sun.nio.fs.UnixException.translateToIOException(UnixException.java:91) ~[na:1.8.0_71]
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102) ~[na:1.8.0_71]
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107) ~[na:1.8.0_71]
at sun.nio.fs.UnixFileSystemProvider.newDirectoryStream(UnixFileSystemProvider.java:427) ~[na:1.8.0_71]
at java.nio.file.Files.newDirectoryStream(Files.java:457) ~[na:1.8.0_71]
at java.nio.file.Files.list(Files.java:3451) ~[na:1.8.0_71]
at com.kg.datahub.service.impl.CleanupServiceImpl.getFiles(CleanupServiceImpl.java:50) ~[kg-datahub-framework-1.0-SNAPSHOT.jar:na]
at com.kg.datahub.job.FilesCleanupJob.execute(FilesCleanupJob.java:42) ~[kg-datahub-framework-1.0-SNAPSHOT.jar:na]
at sun.reflect.GeneratedMethodAccessor414.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_71]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_71]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) ~[spring-context-4.1.5.RELEASE.jar:4.1.5.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-4.1.5.RELEASE.jar:4.1.5.RELEASE]
下面是我的FileCleanupJob代码(使用了try with resources)
try(最终流olderArchiveFiles=cleanupService.getFiles(path.get(csvArchiveDirectory)、CSV\u FILE\u PATTHERN、thresholdDate)){
LOG.info(“删除存档文件…”);
cleanupService.deleteFiles(旧归档文件);
}
下面是清理服务代码
@Override
public Stream<Path> getFiles(final Path locationPath, final String filePattern, final Date date) throws IOException {
final Pattern pattern = Pattern.compile(filePattern);
final DateFormat dateFormat = new SimpleDateFormat(datePattern);
final Function<Path, String> captureDatePart = path -> {
final String fileName = path.getFileName().toString();
final Matcher matcher = pattern.matcher(fileName);
return matcher.find() ? matcher.group(1) : StringUtils.EMPTY;
};
final Function<String, Date> convertToDate = datePart -> {
try {
return dateFormat.parse(datePart);
} catch (ParseException e) {
throw Throwables.propagate(e);
}
};
final Function<Date, Boolean> checkIsOlder = fileDate -> fileDate.before(date);
final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(globPattern);
return Files.list(locationPath).filter(Files::isRegularFile).filter(pathMatcher::matches).filter(captureDatePart.andThen(convertToDate).andThen(checkIsOlder)::apply);
}
@Override
public void deleteFiles(Stream<Path> files) {
files.map(Path::toFile).forEach(File::delete);
}
@覆盖
公共流getFiles(最终路径locationPath、最终字符串文件模式、最终日期)引发IOException{
最终模式=Pattern.compile(filePattern);
最终日期格式DateFormat=新的SimpleDateFormat(日期模式);
最终函数captureDatePart=路径->{
最终字符串文件名=path.getFileName().toString();
final Matcher Matcher=pattern.Matcher(文件名);
返回matcher.find()?matcher.group(1):StringUtils.EMPTY;
};
最终函数convertToDate=datePart->{
试一试{
returndateformat.parse(datePart);
}捕获(解析异常){
抛掷物。传播(e);
}
};
最终函数checkIsOlder=fileDate->fileDate.before(日期);
最终路径匹配器PathMatcher=FileSystems.getDefault().getPathMatcher(globPattern);
返回Files.list(locationPath).filter(Files::isRegularFile).filter(pathMatcher::matches).filter(captureDatePart.and then(convertToDate.and then(CheckIsOrder)::应用);
}
@凌驾
公共无效删除文件(流文件){
files.map(Path::toFile).forEach(File::delete);
}
有什么建议吗?对我来说已经晚了,但我似乎记得我们在错误消息不完全正确的地方看到了类似的情况。问题是,IIRC,我们在TC应用程序中拥有的线程数量超过了ulimit,但这意味着一个开放文件问题。我们通过增加O/S级别的进程限制来解决这个问题。我可能记错了。你在用这些路径做什么?可能问题出在deleteFiles方法中(或其他打开文件但从不关闭文件的方法中)。@JBNizet Stream被传递到deleteFiles方法,我将在其中删除每个相应的文件。已更新问题以包含deleteFiles代码段。如日志所示,调用getFiles方法时发生异常。在本地系统和较低的环境中,我没有遇到这样的问题。假设您最多可以打开1000个文件描述符。如果在方法foo()和bar()中打开1000个,但忘记关闭它们,然后调用方法getFiles(),尝试打开第1001个。这就是抛出异常的地方,但问题出在foo()和bar()中,它们没有正确关闭文件。这是我的观点。不是说这是个问题,而是说它可能是个问题。
@Override
public Stream<Path> getFiles(final Path locationPath, final String filePattern, final Date date) throws IOException {
final Pattern pattern = Pattern.compile(filePattern);
final DateFormat dateFormat = new SimpleDateFormat(datePattern);
final Function<Path, String> captureDatePart = path -> {
final String fileName = path.getFileName().toString();
final Matcher matcher = pattern.matcher(fileName);
return matcher.find() ? matcher.group(1) : StringUtils.EMPTY;
};
final Function<String, Date> convertToDate = datePart -> {
try {
return dateFormat.parse(datePart);
} catch (ParseException e) {
throw Throwables.propagate(e);
}
};
final Function<Date, Boolean> checkIsOlder = fileDate -> fileDate.before(date);
final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(globPattern);
return Files.list(locationPath).filter(Files::isRegularFile).filter(pathMatcher::matches).filter(captureDatePart.andThen(convertToDate).andThen(checkIsOlder)::apply);
}
@Override
public void deleteFiles(Stream<Path> files) {
files.map(Path::toFile).forEach(File::delete);
}