Mic*_*Kay 7 java directory-structure
我已经实现了(在Java中)一个相当简单的迭代器来返回递归目录结构中文件的名称,并且在大约2300个文件之后它失败了"系统中打开的文件太多"(失败实际上是在尝试加载一个类,但我认为目录列表是罪魁祸首).
迭代器维护的数据结构是一个堆栈,其中包含在每个级别打开的目录的内容.
实际逻辑是相当基本的:
private static class DirectoryIterator implements Iterator<String> {
private Stack<File[]> directories;
private FilenameFilter filter;
private Stack<Integer> positions = new Stack<Integer>();
private boolean recurse;
private String next = null;
public DirectoryIterator(Stack<File[]> directories, boolean recurse, FilenameFilter filter) {
this.directories = directories;
this.recurse = recurse;
this.filter = filter;
positions.push(0);
advance();
}
public boolean hasNext() {
return next != null;
}
public String next() {
String s = next;
advance();
return s;
}
public void remove() {
throw new UnsupportedOperationException();
}
private void advance() {
if (directories.isEmpty()) {
next = null;
} else {
File[] files = directories.peek();
while (positions.peek() >= files.length) {
directories.pop();
positions.pop();
if (directories.isEmpty()) {
next = null;
return;
}
files = directories.peek();
}
File nextFile = files[positions.peek()];
if (nextFile.isDirectory()) {
int p = positions.pop() + 1;
positions.push(p);
if (recurse) {
directories.push(nextFile.listFiles(filter));
positions.push(0);
advance();
} else {
advance();
}
} else {
next = nextFile.toURI().toString();
count++;
if (count % 100 == 0) {
System.err.println(count + " " + next);
}
int p = positions.pop() + 1;
positions.push(p);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想了解这需要多少"打开文件".在什么情况下这个算法"打开"一个文件,什么时候再次关闭?
我看过一些使用Java 7或Java 8的简洁代码,但我受限于Java 6.
调用nextFile.listFiles()时,将打开基础文件描述符以读取目录.无法显式关闭此描述符,因此您依赖于垃圾回收.当你的代码下降到一棵深树时,它本质上是收集一堆nextFile实例,这些实例无法被收集.
步骤1:在调用advance()之前设置nextFile = null.这将释放垃圾回收对象.
第2步:在将nextFile归零后,您可能需要调用System.gc()以鼓励快速垃圾回收.不幸的是,没有办法强制GC.
第3步:您可能需要增加操作系统的打开文件限制.在Linux上,这可以使用ulimit(1)完成.
如果您可以迁移到Java 7或更高版本,则DirectoryStream将解决您的问题.而不是使用nextFile.listFiles(),使用Files.newDirectoryStream(nextFile.toPath())来获取DirectoryStream.然后,您可以遍历流,然后关闭()它以释放操作系统资源.可以使用toFile()将每个返回的路径转换回文件.但是,您可能希望重构仅使用Path而不是File.
| 归档时间: |
|
| 查看次数: |
745 次 |
| 最近记录: |