java遍历文件的几种方法

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


1. 自己写函数递归
2. google的guava工具包
3. common io工具包
4. 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;
			}

		});
	}
}

程序执行结果如下:

152058
byFunction:6584 ms
178667
guavaBreadthFirst:5539 ms
178667
guavaDepthFirst:5153 ms
152058
byCommonio:6543 ms
152058
byJdkFiles:2272 ms

执行3次结果统计:

(ms)自己递归guava广度优先guava深度优先common iojdk.nio.Files
165845539515365432272
267556521566173102834
359905723545069752345
平均64435927542169422483

jdk自带的Files类比自己递归节约了: (6443 - 2483)÷6443 = 61%的时间. 有些情况下甚至可以节约80%以上的时间. 所以还有什么理由再去自己写算法呢?
除了遍历文件,还有复制文件也是如此,参见另一篇:java复制文件的三种方法
当性能想要大幅提高的时候,先去java类库找有没有合适的工具类.如果没有再考虑其他jar包. 另外发现,common的jar包一般性能不是很好, 可能偏重于可靠性, google的工具包要好一些.

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值