递归遍历文件夹
java 8之前遍历文件夹用File.list(),而rxjava要想遍历文件夹,那么最简单的做法是递归遍历。
public Observable<File> recursiveDir(final File parent) {
if (!parent.isDirectory()) {
return Observable.just(parent);
}
File[] files = null;
if ((files = parent.listFiles()) == null || files.length == 0){}
return Observable.empty();
}
return Observable.fromArray(files)
.flatMap(new Function<File, Observable<File>>() {
@Override
public Observable<File> apply(File file) throws Exception {
return recursiveDir(file);
}
});
}
递归的写法简单写起来爽,不过跑起来就要哭死你了,StackOverflow!OutOfMemory!。不信试试遍历下手机sdcard下面的tencent目录,不是巨慢就是崩溃!
堆栈遍历文件夹
rxJava递归遍历文件夹除了本身递归在队栈保存恢复上消耗系统资源,还因为rxjava在每一层递归中产生一个Observable,而Observable如果是并发的很可能很快就消耗尽线程池资源。既然递归方式不行,那就改成自己维护堆栈的方式遍历呗,直接看代码吧
/**
* Created by droidwolf on 2017/11/14.
* https://my.oschina.net/droidwolf
* 转载请注明
*/
public class FileTreeWalker implements Iterable<File> {
private ArrayDeque<File> mDirectories =null;
private ArrayDeque<File> mFiles = null;
public FileTreeWalker walk(File path) {
if (mDirectories != null && !mDirectories.isEmpty()) {
mDirectories.clear();
}
if (mFiles != null && !mFiles.isEmpty()) {
mFiles.clear();
}
walkDir(path);
return this;
}
private void walkDir(File path) {
if (path == null || !path.exists() || !path.isDirectory()) {
return;
}
final File[] files = path.listFiles();
if (files == null || files.length == 0) {
return;
}
if(mDirectories==null) mDirectories = new ArrayDeque<File>(256);
if(mFiles==null) mFiles = new ArrayDeque<File>(512);
for (File f : files) {
if (f.isDirectory()) {
mDirectories.push(f);
} else {
mFiles.addLast(f);
}
}
}
@Override
public Iterator<File> iterator() {
return mIterator;
}
private final Iterator<File> mIterator=new Iterator<File>() {
@Override
public boolean hasNext() {
return (mFiles!=null &&!mFiles.isEmpty()) || (mDirectories!=null&& !mDirectories.isEmpty());
}
@Override
public File next() {
if (mFiles != null && !mFiles.isEmpty()) {
final File f = mFiles.pollFirst();
return f;
} else if (mDirectories != null && !mDirectories.isEmpty()) {
final File dir = mDirectories.pop();
walkDir(dir);
return dir;
}
return null;
}
};
}
rxjava调用FileTreeWalker
Observable.fromIterable(new FileTreeWalker().walk(path))
.subscribeOn(Schedulers.io())
.filter(file -> {
//。。。
return false;
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(fileNext -> {
//。。。
});
当然也可以在java8中使用FileTreeWalker
StreamSupport.stream(Spliterators.spliteratorUnknownSize(new FileTreeWalker().walk(new File("C:\\")).iterator(),Spliterator.NONNULL),true )
.forEach(file->{
if(file.isDirectory()) {
System.out.println(file.getName());
}else {
System.out.println("\t"+file.getName());
}
});
总结
递归很多时候写的爽快但遇到瓶颈时优化是个头疼的问题,如果语言自带尾递归优化外挂那还好,没有的话还是得改变原来的思路重来。最后得说一下这个FileTreeWalker实际是不安全的,因为它持有文件夹和文件队列,这使得FileTreeWalker在遍历过程中产生状态的变化,如果在多线程中这是个忌讳。至于怎么改,自己看着办吧!:(