Java NIO FileVisitor 高效刪除文件

      在公司項目中,因爲作個二維碼掃碼平臺項目,預計天天產生的二維碼圖片達到十幾G,因此要作個定時清理任務來定時清理圖片,根據不一樣場景保留圖片,規則是:一、二維碼統一登陸圖片幾個小時有效   二、電子名片二維碼前幾天有效,這些參數都是可配置的。java

剛開始時,直接用Io 文件操做,遞歸刪除文件,根據場景判斷刪除邏輯。可是,壓力測試後發現,刪除十幾G文件要20分鐘,直接測試不過。緣由分析:在全部的5級目錄下,要遍歷匹配條件的文件,將不符合文件的刪除,刪除又用了遞歸,全部一下有三層循環,這樣直接遍歷數據太大,性能直接降低,後來在網上看到NIO 裏面有種快速遍歷的方法,就是FileVisitor ,因而,本身看了下這個接口的API ,最後本身寫了下,在過程當中,遇到很多的坑。app

      首先,瞭解下FileVisitor 裏面有四個方法,表明的分別是訪問文件的四個狀態:訪問目錄前,訪問目錄時,訪問文件時,訪問文件失敗後,這是個方法分別能夠返回:CONTINUE 繼續、SKIP_SIBLINGS:繼續遍歷,但忽略當前節點的全部兄弟節點直接返回上一層繼續遍歷、SKIP_SUBTREE:繼續遍歷,可是忽略子目錄,可是子文件仍是會訪問;TERMINATE:終止遍歷。ide

    運行機制:首先根據文件目錄來判斷走哪一個文件目錄,首先程序跑到preVisitDirectory 這個方法裏面,根據本身設計的邏輯走到不一樣的路徑中,在這裏你能夠本身設置走到當前的目錄時,不走下一級目錄,直接忽略子目錄,或者終止遍歷,該方法主要是判斷遍歷那個文件目錄。而後程序走完這個方法時,再跑到這個方法:postVisitDirectory 這個主要是遍歷當前文件目錄當遍歷到文件時,就跑到VisitFile 裏面去,VisitFile 主要是拿到當前文件目錄下的文件,而後刪除該文件,刪除完了,postVisitDirectory  將改文件目錄刪除。而後依次如此......post

定義一個類,繼承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;
}ui

@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;
}orm

 

刪除文件的具體實現,這個是本地測試的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); }}

相關文章
相關標籤/搜索