OK、これを行うために独自のイテレータを実装することになりました(Amirが提案したように)。それは正確に些細なことではありませんでしたが(幸いなことに、誰かがイテレータをフラット化するコードをすでに書いていますが)、かなり簡単です。
メモリ内の単一のディレクトリ(子孫なし)の完全なリストを保持しているため、フラットなディレクトリレイアウトには使用できません(この場合、Java 7まで純粋なJavaを使用するのは運が悪いと思います)が、これまでのところ機能しています私のユースケースにははるかに優れています。
RecursiveFileIterable.java
:
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class RecursiveFileIterable implements Iterable<File> {
private File file;
public RecursiveFileIterable(File f) {
file = f;
}
public RecursiveFileIterable(String filename) {
this(new File(filename));
}
private class DirectoriesOnlyFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
}
private class NoDirectoriesFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
return !pathname.isDirectory();
}
}
@Override
public Iterator<File> iterator() {
List<File> normFiles = Arrays.asList(file
.listFiles(new NoDirectoriesFilter()));
ArrayList<Iterable<File>> pendingIterables = new ArrayList<Iterable<File>>();
pendingIterables.add(normFiles);
File[] subdirs = file.listFiles(new DirectoriesOnlyFilter());
for (File sd : subdirs)
pendingIterables.add(new RecursiveFileIterable(sd));
return new FlattenIterable<File>(pendingIterables).iterator();
}
}
FlattenIterable.java
:
// from http://langexplr.blogspot.com.au/2007/12/combining-iterators-in-java.html
import java.util.Iterator;
public class FlattenIterable<T> implements Iterable<T> {
private Iterable<Iterable<T>> iterable;
public FlattenIterable(Iterable<Iterable<T>> iterable) {
this.iterable = iterable;
}
public Iterator<T> iterator() {
return new FlattenIterator<T>(iterable.iterator());
}
static class FlattenIterator<T> implements Iterator<T> {
private Iterator<Iterable<T>> iterator;
private Iterator<T> currentIterator;
public FlattenIterator(Iterator<Iterable<T>> iterator) {
this.iterator = iterator;
currentIterator = null;
}
public boolean hasNext() {
boolean hasNext = true;
if (currentIterator == null) {
if (iterator.hasNext()) {
currentIterator = iterator.next().iterator();
} else {
return false;
}
}
while (!currentIterator.hasNext() && iterator.hasNext()) {
currentIterator = iterator.next().iterator();
}
return currentIterator.hasNext();
}
public T next() {
return currentIterator.next();
}
public void remove() {
}
}
}