您的位置 首页 java

java遍历文件的几种方法

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


  1. 自己写函数递归
  2. google的guava工具包
  3. common io工具包
  4. jdk自带的n io 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次结果统计:

3次执行时间

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

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

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

文章来源:智云一二三科技

文章标题:java遍历文件的几种方法

文章地址:https://www.zhihuclub.com/195606.shtml

关于作者: 智云科技

热门文章

网站地图