Java NIO FileVisitor 高效删除文件
在公司项目中,由于做个二维码扫码平台项目,预计每天产生的二维码图片达到十几G,所以要做个定时清理任务来定时清理图片,根据不同场景保留图片,规则是:1、二维码统一登录图片几个小时有效 2、电子名片二维码前几天有效,这些参数都是可配置的。
刚开始时,直接用Io 文件操作,递归删除文件,根据场景判断删除逻辑。但是,压力测试后发现,删除十几G文件要20分钟,直接测试不过。原因分析:在所有的5级目录下,要遍历匹配条件的文件,将不符合文件的删除,删除又用了递归,所有一下有三层循环,这样直接遍历数据太大,性能直接下降,后来在网上看到NIO 里面有种快速遍历的方法,就是FileVisitor ,于是,自己看了下这个接口的API ,最后自己写了下,在过程中,遇到不少的坑。
首先,了解下FileVisitor 里面有四个方法,代表的分别是访问文件的四个状态:访问目录前,访问目录时,访问文件时,访问文件失败后,这是个方法分别可以返回:CONTINUE 继续、SKIP_SIBLINGS:继续遍历,但忽略当前节点的所有兄弟节点直接返回上一层继续遍历、SKIP_SUBTREE:继续遍历,但是忽略子目录,但是子文件还是会访问;TERMINATE:终止遍历。
运行机制:首先根据文件目录来判断走哪个文件目录,首先程序跑到preVisitDirectory 这个方法里面,根据自己设计的逻辑走到不同的路径中,在这里你可以自己设置走到当前的目录时,不走下一级目录,直接忽略子目录,或者终止遍历,该方法主要是判断遍历那个文件目录。然后程序走完这个方法时,再跑到这个方法:postVisitDirectory 这个主要是遍历当前文件目录当遍历到文件时,就跑到VisitFile 里面去,VisitFile 主要是拿到当前文件目录下的文件,然后删除该文件,删除完了,postVisitDirectory 将改文件目录删除。然后依次如此......
定义一个类,继承FileVIsitor 这个接口,下面的主要是继承这个接口然后重写四个方法
@Override
	public FileVisitResult preVisitDirectory(Object dir,
			BasicFileAttributes attrs) throws IOException {
		// TODO Auto-generated method stub
		return null;
	}
@Override
	public FileVisitResult visitFile(Object file, BasicFileAttributes attrs)
			throws IOException {
		// TODO Auto-generated method stub
		return null;
	}
@Override
	public FileVisitResult visitFileFailed(Object file, IOException exc)
			throws IOException {
		// TODO Auto-generated method stub
		return null;
	}
@Override
	public FileVisitResult postVisitDirectory(Object dir, IOException exc)
			throws IOException {
		// TODO Auto-generated method stub
		return null;
	}
删除文件的具体实现,这个是本地测试的Demo 版 ps:代码写得有点乱,来不及整理。
package com.tony.test;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumSet;
public class DeleteFile implements FileVisitor {
private static DeleteFile deletefileInstace;
	public static DeleteFile getInstance() {
		if (deletefileInstace == null) {
			synchronized (DeleteFile.class) {
				if (deletefileInstace == null) {
					deletefileInstace = new DeleteFile();
				}
			}
		}
		return deletefileInstace;
	}
	@Override
	public FileVisitResult preVisitDirectory(Object dir,
			BasicFileAttributes attrs) throws IOException {
		String f=dir.toString();
		if(!deleteByDaysOuttime(0,(Path)dir))
		{
			System.out.println("preVisitDirectory f:按天删除跳进来了"+f);
			return FileVisitResult.SKIP_SUBTREE;
		}
		else if(!deleteByHoursOuttime(3, (Path)dir)) //按小时删除
		{
			System.out.println("preVisitDirectory f:按小时删除跳进来了"+f);
			return FileVisitResult.SKIP_SUBTREE;
		}
		return FileVisitResult.CONTINUE;
	}
@Override
	public FileVisitResult visitFile(Object file, BasicFileAttributes attrs)
			throws IOException {
		 boolean success = deleteFileByFile((Path) file);
return FileVisitResult.CONTINUE;
	}
@Override
	public FileVisitResult visitFileFailed(Object file, IOException exc)
			throws IOException {
		return FileVisitResult.CONTINUE;
	}
@Override
	public FileVisitResult postVisitDirectory(Object file, IOException exc)
			throws IOException {
		boolean success=false;
		/*System.out.println("postVisitDirectory 你在哪 F"+file.toString());*/
		if (exc == null) {
			/*File.separator*/
			String f=file.toString();
			Path path=(Path)file;
			StringBuilder stringBuilder=new StringBuilder();
			stringBuilder.append("E:").append(File.separator)
			.append("home").append(File.separator).append("qr").append(File.separator)
			.append("1");
			System.out.println("File path"+stringBuilder.toString());
			//按天删除
			if(deleteByDaysOuttime(0,(Path)file)&&!f.equals(stringBuilder.toString()))
		    {
				System.out.println("Path Count : "+path.getNameCount());
				   System.out.println("postVisitDirectory 老子跳进坑了 F"+file.toString());
				   success = deleteFileByFile((Path) file);
				
				if (success) {
					System.out.println("dir Deleted: " + (Path) file);
				} else {
					System.out.println("dir Not deleted: " + (Path) file);
				}
		 }else if(deleteByHoursOuttime(2,(Path)file)&&!f.equals("E:\\home\\qr\\1\\20171209\\"))//按小时的1场景删除
		 {
			 success = deleteFileByFile((Path) file);
				
				if (success) {
					System.out.println("dir Deleted: " + (Path) file);
				} else {
					System.out.println("dir Not deleted: " + (Path) file);
				}
		 }
		} else {
			throw exc;
		}
		return FileVisitResult.CONTINUE;
	}
private	boolean deleteFileByFile(Path file){
		boolean flag=false;
		try {
			flag= Files.deleteIfExists(file);
		} catch (Exception e) {
			// TODO: handle exception			
		}
		return flag;
		
	}
/**
	 * 
	 * 按天数来删除,刪除days 之前的文件夹
	 * 
	 * @param days
	 */
	private boolean deleteByDaysOuttime(int days, Path file) {
		boolean flag = true;
		String rootPathString="E:\\home\\qr\\2\\";
		for(int i=0;i<=days;i++){			
			String getFileNameByDays=getDays(i);
			if (file.toString().equals(rootPathString+getFileNameByDays)) { //不删除
				flag = false;
				System.out.println("不要删掉的文件目录:"+file);				
			}
		}
		return flag;
	}
private boolean deleteByHoursOuttime(int hours, Path file) {
		boolean flag = true;
		String rootPathString="E:\\home\\qr\\1\\20171209\\";
		for(int i=0;i<=hours;i++){
			String getFileNameByHours=getHours(i);
			/*System.out.println("当前遍历的文件:"+file.getFileName());
			System.out.println("自己算出的文件名"+getFileNameByHours);*/
			if (file.toString().equals(rootPathString+getFileNameByHours)) { //不删除
				flag = false;
			}
		}
		return flag;
	}
/**
	 * 获取当前时间的前几天时间  
	 * @param days
	 * @return 返回yyyyMMdd时间格式的文件名
	 */
	private String getDays(int days) {
		Calendar calendar=Calendar.getInstance();
		calendar.add(Calendar.DAY_OF_MONTH, -days);
		SimpleDateFormat sFormat=new SimpleDateFormat("yyyyMMdd");
		return sFormat.format(calendar.getTime());
	}
	
	
	/**
	 * 获取当前时间的前几小时时间  
	 * @param days
	 * @return 返回yyyyMMdd时间格式的文件名
	 */
	private String getHours(int hours) {
		Calendar calendar=Calendar.getInstance();
		calendar.add(Calendar.HOUR, -hours);
		SimpleDateFormat sFormat=new SimpleDateFormat("HH");
		return sFormat.format(calendar.getTime());
	}
public static void main(String[] args) {
		/*System.out.println(deletefileInstace.getInstance().getDays(1));*/
		
		System.out.println("按小时删除");
		long start = System.currentTimeMillis();
		int scence=1;
		Path directory=null;
		deletefileInstace=deletefileInstace.getInstance();
		StringBuilder sbBuilder=new StringBuilder();		
		//场景1
		////删除今天以为的文件夹
		if(scence>0)
		{
		   sbBuilder.append("E:\\home\\qr\\1").append(File.separator).append(getInstance().getDays(0));
		   directory = Paths.get(sbBuilder.toString());
		   System.out.println(sbBuilder.toString());
		   EnumSet opts1 = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
		   try {
				Files.walkFileTree(directory, opts1, Integer.MAX_VALUE, deletefileInstace);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		   
		    
		}else if(scence>0)
		{
			sbBuilder=new StringBuilder();
			   sbBuilder.append("E:\\home\\qr\\2");
			   directory = Paths.get(sbBuilder.toString());
			   EnumSet opts3 = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
			   try {
					Files.walkFileTree(directory, opts3, Integer.MAX_VALUE, deletefileInstace);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	    
		System.out.println(System.currentTimeMillis() - start);
		
		 
		
	}
}
Java NIO FileVisitor 高效删除文件的更多相关文章
- JAVA NIO FileChannel 内存映射文件
		文件通道总是阻塞式的. 文件通道不能创建,只能通过(RandomAccessFile.FileInputStream.FileOutputStream)getChannel()获得,具有与File ... 
- java File delete 无法删除文件的原因。
		windows下使用java.io.File.delete()方法删除文件时,返回值为true. 但是本地文件仍然存在,也就是说没有删除成功. 这时候你要检查下你传进来的文件目录格式是否正确. 正确: ... 
- Java NIO之内存映射文件——MappedByteBuffer
		大多数操作系统都可以利用虚拟内存实现将一个文件或者文件的一部分"映射"到内存中.然后,这个文件就可以当作是内存数组来访问,这比传统的文件要快得多. 内存映射文件的一个关键优势是操作 ... 
- Java IO和Java NIO 和通道 在文件拷贝上的性能差异分析
		1. 在JAVA传统的IO系统中,读取磁盘文件数据的过程如下: 以FileInputStream类为例,该类有一个read(byte b[])方法,byte b[]是我们要存储读取到用户空间的缓冲区 ... 
- java IO流实现删除文件夹以及文件夹中的内容
		这篇主要是对IO文件流对文件常用处理中的删除文件夹,平时我们直接删除文件夹既可以删除里面的全部内容. 但是java在实现删除时,只能是文件才会被删除. 所以这里需要定义一个方法,来递归调用方法(递归调 ... 
- java基础 File 递归删除文件夹中所有文件文件夹  目录(包含子目录)下的.java文件复制到e:/abc文件夹中, 并统计java文件的个数
		File 递归删除文件夹中所有文件文件夹 package com.swift.kuozhan; import java.io.File; import java.util.Scanner; /*键盘录 ... 
- 【java工具类】删除文件及目录
		FileUtil.java /** * 删除文件及目录 * @param file; */ public static boolean delFile(File file) { if (!file.e ... 
- java nio读取和写入文件
		读取 package com.test; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputS ... 
- java调用cmd命令删除文件夹及其所有内容
		/** * *删除D盘下面test目录,感觉以前用io流遍历删除好慢! * **/ public static void main(String[] args) { Runtime run = Run ... 
随机推荐
- Java经典编程题50道之二十一
			求1+2!+3!+...+20!的和. public class Example21 { public static void main(String[] args) { sum( ... 
- SDP(8):文本式数据库-MongoDB-Scala基本操作
			MongoDB是一种文本式数据库.与传统的关系式数据库最大不同是MongoDB没有标准的格式要求,即没有schema,合适高效处理当今由互联网+商业产生的多元多态数据.MongoDB也是一种分布式数据 ... 
- 用batch调用DB2 CLPPlus执行多个SQL文
			不啰嗦直接上技能. 大概三部分组成: 1.bat文件.(run.bat) 2.辅助SQL文.(AllRun.sql) 3.要执行的SQL文.(S1.sql,S2.sql,S3.sql) +++++++ ... 
- web3 - BOM&DOM
			一.BOM (浏览器对象模型) 浏览器对象模型 (BOM) 使 JavaScript 有能力与浏览器"对话". Window 对象 1.window.onresize // 1 w ... 
- Yii2按需加载图片怎么做?
			按需加载图片应该用 jQuery LazyLoad 图片延迟加载按需加载文件夹应该用 Yii::import 
- 由select引发的思考
			一.前言 网络编程里一个经典的问题,selec,poll和epoll的区别?这个问题刚学习编程时就接触了,当时看了材料很不明白,许多概念和思想没有体会,现在在这个阶段,再重新回头看这个问题,有一种豁然 ... 
- HDU - 1067 Gap (bfs + hash) [kuangbin带你飞]专题二
			题意: 起初定28张卡牌的排列,把其中11, 21, 31, 41移动到第一列,然后就出现四个空白,每个空白可以用它的前面一个数的下一个数填充,例如43后面的空格可以用44填充,但是47后面即 ... 
- JAVA 处理 Spring data mongodb 时区问题
			Spring data mongodb 查询出结果的时候会自动 + 8小时,所以我们看起来结果是对的 但是我们查询的时候,并不会自动 + 8小时,需要自己处理 解决方法 1 @JsonFormat ... 
- P3
			package p3.hadoop.mapred; import java.io.IOException; import java.io.InputStream; import org.apache. ... 
- Git创建本地分支并推送到远程github仓库
