2019独角兽企业重金招聘Python工程师标准>>>
递归遍历文件夹
java 8之前遍历文件夹用File.list(),而rxjava要想遍历文件夹,那么最简单的做法是递归遍历。
public Observable 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>() {@Overridepublic Observable 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 {private ArrayDeque mDirectories =null;private ArrayDeque 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(256);if(mFiles==null) mFiles = new ArrayDeque(512);for (File f : files) {if (f.isDirectory()) {mDirectories.push(f);} else {mFiles.addLast(f);}}}@Overridepublic Iterator iterator() {return mIterator;}private final Iterator mIterator=new Iterator() {@Overridepublic boolean hasNext() {return (mFiles!=null &&!mFiles.isEmpty()) || (mDirectories!=null&& !mDirectories.isEmpty());}@Overridepublic 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在遍历过程中产生状态的变化,如果在多线程中这是个忌讳。至于怎么改,自己看着办吧!:(