zoukankan      html  css  js  c++  java
  • 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);



    }
    }

  • 相关阅读:
    TCP协议
    各相机品牌型号分类
    思科华为命令对比
    网工笔记(一)
    数学笔记
    word快捷键汇总
    请个假
    word笔记
    ScrollView不能到顶部的解决方法
    Gridview 显示成正方形
  • 原文地址:https://www.cnblogs.com/xlh-2014/p/8013230.html
Copyright © 2011-2022 走看看