在公司项目中,由于做个二维码扫码平台项目,预计每天产生的二维码图片达到十几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 高效删除文件的更多相关文章

  1. JAVA NIO FileChannel 内存映射文件

      文件通道总是阻塞式的. 文件通道不能创建,只能通过(RandomAccessFile.FileInputStream.FileOutputStream)getChannel()获得,具有与File ...

  2. java File delete 无法删除文件的原因。

    windows下使用java.io.File.delete()方法删除文件时,返回值为true. 但是本地文件仍然存在,也就是说没有删除成功. 这时候你要检查下你传进来的文件目录格式是否正确. 正确: ...

  3. Java NIO之内存映射文件——MappedByteBuffer

    大多数操作系统都可以利用虚拟内存实现将一个文件或者文件的一部分"映射"到内存中.然后,这个文件就可以当作是内存数组来访问,这比传统的文件要快得多. 内存映射文件的一个关键优势是操作 ...

  4. Java IO和Java NIO 和通道 在文件拷贝上的性能差异分析

    1.  在JAVA传统的IO系统中,读取磁盘文件数据的过程如下: 以FileInputStream类为例,该类有一个read(byte b[])方法,byte b[]是我们要存储读取到用户空间的缓冲区 ...

  5. java IO流实现删除文件夹以及文件夹中的内容

    这篇主要是对IO文件流对文件常用处理中的删除文件夹,平时我们直接删除文件夹既可以删除里面的全部内容. 但是java在实现删除时,只能是文件才会被删除. 所以这里需要定义一个方法,来递归调用方法(递归调 ...

  6. java基础 File 递归删除文件夹中所有文件文件夹 目录(包含子目录)下的.java文件复制到e:/abc文件夹中, 并统计java文件的个数

    File 递归删除文件夹中所有文件文件夹 package com.swift.kuozhan; import java.io.File; import java.util.Scanner; /*键盘录 ...

  7. 【java工具类】删除文件及目录

    FileUtil.java /** * 删除文件及目录 * @param file; */ public static boolean delFile(File file) { if (!file.e ...

  8. java nio读取和写入文件

    读取 package com.test; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputS ...

  9. java调用cmd命令删除文件夹及其所有内容

    /** * *删除D盘下面test目录,感觉以前用io流遍历删除好慢! * **/ public static void main(String[] args) { Runtime run = Run ...

随机推荐

  1. prop&attr区别和用法,以多选框为例

    1.比较 相同点 : prop和attr作为jquery的方法都可以获取属性值; 不同点 : (1) 对于HTML元素本身就带有的固有属性,使用prop方法, attr获取checkbox的check ...

  2. [翻译]编写高性能 .NET 代码 第一章:工具介绍 -- Visual Studio

    <<返回目录 Visual Studio vs虽然不是全宇宙唯一的IDE,但它是.net开发人员最常用的开发工具.它自带一个性能分析工具,你可以使用它来做开发,不同的vs版本在工具上会略有 ...

  3. java库中的具体的集合

    1.ArrayList  一种可以动态增长和缩减的索引序列:速度较慢适合用于不修改太多的元素    采用的数组 2.LinkEdList  一种可以在任何位置进行高效的插入和删除操作的有序序列,适合于 ...

  4. hihoCoder Demo Day dp

    题意:有一个机器人被困在一个的迷宫中,机器人的初始位置是,目的地是,并且它的移动方式很奇怪:只能一直向右,直到不能再向右才能把方向变成向下:只能一直向下,直到不能再向下才能把方向变成向右.迷宫中的每个 ...

  5. php的filesystem基本函数的学习(1)

    1.basename basename — 返回路径中的文件名部分 string basename ( string $path [, string $suffix ] ) 给出一个包含有指向一个文件 ...

  6. 约瑟夫环-循环队列算法(曾微软,google笔试题)

    这也是我们聚会时常常做的游戏之一. 算法思路: 此处我使用循环链表模拟人围城一圈,每一个结点代表一个人.链表是一个有序链表,链表结点数据域是一个整型,代表人的序号.出局等同于链表删除元素,每次出局后重 ...

  7. 工作中常用的linux命令(2)

    1.find :查找指定文件名的路径: 列出当前目录以及子目录中的所有文件: 在当前目录下寻找特定文件名的文件: 列出长度为零的文件: 2.ps :查看某个程序的进程,例如查询mongodb和mysq ...

  8. Django学习-15-Cookie

    Cookie             1.如果没有cookie,那么所有的网站都不能登录             2.客户端浏览器上的文件,keyvalues形式存储的,类似字典           ...

  9. linux配置wifi连接并通过ssh代理开启socks代理

    1, 命令行配置连接wifi具体我是用的cubieboard2上Debian主机,其中配置wifi的命令行有wpa_cli,具体用法步骤如下.wpa_cli 命令行执行需要root权限,详细用法请见 ...

  10. 异常-----spring明明注入了Service到Action中,为什么运行的时候Service为空,在抽象类中,有子类来继承的

    xml的配置文件 <bean id="fftController" class="com.bill99.query.controller.FftController ...