在上一章,我们理清了有哪些该清理的文件,事实上,还有很多文件是可以清理的,如下是百度搜索"垃圾文件给出的定义":
在Windows操作系统安装和使用过程中都会产生相当多的垃圾文件,
包括临时文件(如:*.tmp、*._mp)日志文件(*.log)、
临时帮助文件(*.gid)、磁盘检查文件(*.chk)、
临时备份文件(如:*.old、*.bak)以及其他临时文件。
特别是如果一段时间不清理IE的临时文件夹“Temporary Internet Files”,其中的缓存文件有时会占用上百MB的磁盘空间。
这些垃圾文件不仅仅浪费了宝贵的磁盘空间,严重时还会使系统运行慢如蜗牛。
这点相信你肯定忍受不了吧!所以应及时清理系统的垃圾文件的淤塞,保持系统的“苗条”身材,轻松流畅上网!
关于其他可清理文件类型日后再谈,在这一章我们主要要了解的是,怎么清理?
方案一:写个批量操作的bat文件,然后双击食用.(正如百度百科词条下那个例子)
方案二:使用一门热门的编程语言编写一个含有GUI操作和众多自定义条目的桌面应用程序.
当然了,我们毫无理由再做方案一这种重复而且没有挑战的事情.
那么既然我们选择了方案二,那么就用JAVA编写清理内核,JAVAFX编写GUI吧!
笔者决定从处理垃圾文件的内核开始从内向外的编写,所以现在我们需要完成的功能是编写清理器类,稍微思考构思下,可以想到我们未来的内核可能是这样分布的:
Reader类负责读取文件结构,
SuffixFilter类负责筛选所需要的特定文件类型,
Cleaner类负责遍历文件结构清理.
先编写Reader,思路是使用listFile方法,遍历文件,然后进行迭代来深度遍历找出所有文件出来.
/**
* 得到过滤器下的浅度搜索目标文件下的所有文件
*
* @param path
* 文件地址字符串
*
* @return 正常文件夹返回文件列表,空文件夹和文件返回空数组,地址不存在返回空
*/
public File[] getFiles(String path) {
File file = new File(path);
if (file.exists()) {
if (file.isFile()) {
return new File[0];
}
else {
return file.listFiles();
}
}
else {
return null;
}
}
/**
* 得到过滤器下的深度搜索目标文件下的所有文件
*
* @param path
* 文件地址字符串
*
* @return 一个存放所有文件集合的HashMap
*/
public HashMap<File, File[]> getAllFiles(String path) {
File[] files = getFiles(path);
this.fileMap.put(new File(path), files);
// 如果路径不存在或者是空文件夹或文件,则跳出递归
if (files != null && files.length != 0) {
for (File file : files) {
getAllFiles(file.getPath());
}
}
return this.fileMap;
}
这里笔者使用了HashMap存储文件结构.它能让我清晰的知道哪个文件夹对应的哪些子文件,其中父文件是key,然后子文件们的数组是value.
以上代码基本就是Reader类的核心,现在我们要思索下我们这个Reader类应该具备哪些属性,也就是说,我们需要的哪些数据是应该存储到Reader类的?这直接影响了构造函数和字段.
首先是文件结构HashMap要当做这个类的字段的,这也是这个类存在的原因之一.另外,Reader也不是瞎Read,起码得知道我需要从哪读取,读取什么?
事实上,这是两个问题,首先是从哪读取,我们大可用字符串来构造这个"哪"字,比如C盘:"C:/".然后是读取什么,这也很关键,我们需要清理的是一个垃圾文件的集合,如果所有的文件全部读取出来然后清除大概又要参考我的第一篇文章重装系统了哟.
所以说,我们需要一个过滤器,来过滤出真正的垃圾文件.很幸运,java自己就有这么一个过滤器类:Filter.Filter类里面只有一个方法accept,这个方法返回值是布尔,true代表着通过了过滤,false代表着没有通过,我们重写这个方法就可以指定哪些需要过滤哪些不需要了.
这时候我们需要这个SuffixFilter类了.我们利用这个类继承Filter然后重写它的方法:
package coreCleaner;
import java.io.*;
/**
* @author jinshuguangze
* @version 1.1
*/
public class SuffixFilter implements FilenameFilter {
// 过滤器集,一般以文件类型作为区分,比如{".exe"}就是过滤出应用程序的
private String[] suffix;
/**
* 构造函数
*
* @param suffix
* 过滤字符串数组
*/
public SuffixFilter(String[] suffix) {
this.suffix = suffix;
}
/**
* 重写的过滤方法,使用或运算符号得出是否通过
*
* @param dir
* 要过滤的文件
* @param name
* 文件名
* @return 如果通过过滤就是true,没有通过就是false
*/
@Override
public boolean accept(File dir, String name) {
boolean pass = false;
for (int i = 0; i < suffix.length; i++) {
pass = pass || name.endsWith(suffix[i]);
}
return pass;
}
}
这里面利用了或运算来筛选多个过滤器.
我们其实大可不必专门为它写个类的,直接使用匿名内部类来解决会更方便,不过笔者考虑到程序进一步扩展可能需要指定不同的过滤方案,所以还是把它单独写成一个类了.
有了过滤器,我们就能写一个过滤之前的文件结构产生新文件结构的方法了.
/**
* 得到过滤器下的文件文件结构
*
* @param fileMap
* 文件结构
* @return 过滤后的文件结构
*/
public HashMap<File, File[]> getFilterFiles(HashMap<File, File[]> fileMap) {
// 防止一开始给予的路径就是不存在路径
if (fileMap == null) {
return null;
}
fileMap.forEach((k, v) -> {
// 防止子目录有不存在路径
if (v != null) {
Vector<File> acceptFile = new Vector<>();
SuffixFilter filter = new SuffixFilter(suffix);
for (File file : v) {
if (filter.accept(file.getParentFile(), file.getName())) {
acceptFile.add(file);
}
}
// 如果没有文件满足过滤器,那么put进去的是个空数组
this.fileMapFilter.put(k, acceptFile.toArray(new File[acceptFile.size()]));
}
});
return this.fileMapFilter;
}
PS:可能其中的filter.accept()会看上去比较愚蠢,因为可以直接利用逻辑关系写个方法就行了而不用专门写个类,不过笔者还是坚信在发展中,需求会越来越膨胀的,而且file.listFiles()方法里面可以直接加这个Filter参数,效果会很好:\
这时候我们很明确的知道我们需要的字段有:需要从哪处理的根目录,过滤器,根目录下所有文件集,过滤器下所有文件集.(事实上能从上面的代码中看出来,这是因为笔者提前写好代码的原因,如果不知道这点的话还是得花点时间来思索考量的)
这时我们的Reader类基本只差一些零零散散的setter,getter了.值得注意的是,关于setter笔者只开放了过滤器的setter,代码是这样的:
/**
* 设置过滤器
*
* @param suffix
*/
public void setSuffix(String... suffix) {
this.suffix = suffix;
getFilterFiles(this.fileMap);
}
这是由于文件结构读取出来了,可以快速的更换过滤器来求出它的子集,而开放其余几个字段是毫无意义的.
值得一提的是,在构造器方面,为了保证这个类每次构造出新的对象就直接读取,可以直接在构造器中加方法:
/**
* 构造函数
*
* @param rootPath
* 根文件地址字符串
* @param suffix
* 过滤字符串数组
*/
public Reader(String rootPath, String... suffix) {
this.rootPath = rootPath;
this.suffix = suffix;
getFilterFiles(getAllFiles(rootPath));
}
这个文章过后我们基本把过滤器类和读取类写完了,下篇文章我们讨论清除类和其他一些类的思路.