龙空技术网

java遍历文件的几种方法

Drqf 768

前言:

当前姐妹们对“文件遍历算法”大约比较着重,咱们都想要了解一些“文件遍历算法”的相关资讯。那么小编也在网络上收集了一些关于“文件遍历算法””的相关知识,希望同学们能喜欢,你们一起来了解一下吧!

在java中遍历目录下的所有文件,很多人第一个想到的是用File.listFiles方法递归. 然而这并不是最好的方法, 这里跟几个其他的方法做一个对比.


自己写函数递归google的guava工具包common io工具包jdk自带的nio Files工具类

package test.walkfile;import java.io.File;import java.io.IOException;import java.nio.file.FileVisitResult;import java.nio.file.Path;import java.nio.file.SimpleFileVisitor;import java.nio.file.attribute.BasicFileAttributes;import java.util.Collection;import java.util.concurrent.ConcurrentSkipListSet;import org.apache.commons.io.FileUtils;import org.apache.commons.io.filefilter.TrueFileFilter;import com.google.common.io.Files;import util.TimeUtil;public class WalkFile {	private static final String rootPath = "D:\\";	public static void main(String[] args) throws IOException {		Collection<File> res = new ConcurrentSkipListSet<>();		File root = new File(rootPath);		TimeUtil.timeStart("byFunction");		byFunction(root, res);		System.out.println(res.size());		TimeUtil.timeEnd("byFunction");		res.clear();		TimeUtil.timeStart("guavaBreadthFirst");		guavaBreadthFirst(root, res);		System.out.println(res.size());		TimeUtil.timeEnd("guavaBreadthFirst");		res.clear();		TimeUtil.timeStart("guavaDepthFirst");		guavaDepthFirst(root, res);		System.out.println(res.size());		TimeUtil.timeEnd("guavaDepthFirst");		res.clear();		TimeUtil.timeStart("byCommonio");		byCommonio(root, res);		System.out.println(res.size());		TimeUtil.timeEnd("byCommonio");		res.clear();		TimeUtil.timeStart("byJdkFiles");		byJdkFiles(root, res);		System.out.println(res.size());		TimeUtil.timeEnd("byJdkFiles");		res.clear();	}	/**	 * 自己写算法遍历文件.	 * 	 * @param root	 * 根路径	 * @param allFiles	 * 遍历结果集合	 */	private static void byFunction(File root, Collection<File> allFiles) {		if (root == null || !root.exists()) {			return;		}		if (root.isFile()) {			allFiles.add(root);		} else {			File[] listFiles = root.listFiles();			if (listFiles != null) {				for (File childFile : listFiles) {					byFunction(childFile, allFiles);				}			}		}	}	/**	 * guava 广度优先遍历文件.	 * 	 * @param root	 * 根路径	 * @param allFiles	 * 遍历结果集合	 */	private static void guavaBreadthFirst(File root, Collection<File> allFiles) {		Iterable<File> files = Files.fileTraverser().breadthFirst(root);		files.forEach(f -> allFiles.add(f));	}	/**	 * guava 深度优先遍历文件.	 * 	 * @param root	 * 根路径	 * @param allFiles	 * 遍历结果集合	 */	private static void guavaDepthFirst(File root, Collection<File> allFiles) {		Iterable<File> files = Files.fileTraverser().depthFirstPostOrder(root);		files.forEach(f -> allFiles.add(f));	}	/**	 * 通过common io工具包遍历文件.	 * 	 * @param root	 * 根路径	 * @param allFiles	 * 遍历结果集合	 */	private static void byCommonio(File root, Collection<File> allFiles) {		allFiles.addAll(FileUtils.listFiles(root, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE));	}	/**	 * 通过jdk的nio Files工具类遍历文件.	 * 	 * @param root	 * 根路径	 * @param allFiles	 * 遍历结果集合	 * @throws IOException	 * IO异常	 */	private static void byJdkFiles(File root, Collection<File> allFiles) throws IOException {		java.nio.file.Files.walkFileTree(root.toPath(), new SimpleFileVisitor<Path>() {			@Override			public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {				allFiles.add(file.toFile());				return super.visitFile(file, attrs);			}			@Override			public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {				return FileVisitResult.CONTINUE;			}		});	}}

程序执行结果如下:

152058byFunction:6584 ms178667guavaBreadthFirst:5539 ms178667guavaDepthFirst:5153 ms152058byCommonio:6543 ms152058byJdkFiles:2272 ms

执行3次结果统计:

3次执行时间

jdk自带的Files类比自己递归节约了: (6443 - 2483)÷6443 = 61%的时间. 有些情况下甚至可以节约80%以上的时间. 所以还有什么理由再去自己写算法呢?

除了遍历文件,还有复制文件也是如此. jdk nio的Files工具类用时大概是普通buffer数组方式的1/3, FileChannel和Files差不多一样快.

当性能想要大幅提高的时候,先去java类库找有没有合适的工具类.如果没有再考虑其他jar包. 另外发现,common的jar包一般性能不是很好, 可能偏重于可靠性, google的工具包要好一些.

标签: #文件遍历算法