使用背景:
加入你有一堆的图片,有一天你想整理一下,想删除重复或者相似度较高的图,自己手动又太累太耗时...
主类:
import com.sun.jna.platform.FileUtils;
import tool.PublicWays;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
public class DeleteDuplicateImg {
private static File txtFile;
private static String foreachFolder;
public DeleteDuplicateImg(File file, String downloadUrl) {
if (file != null)
txtFile = file;
else {
txtFile = new File("DownloadImageLog.txt");//为空或仅执行当前类时指定创建txt文件
PublicWays.creatFile(txtFile);
}
if (downloadUrl != null)
foreachFolder = downloadUrl;
else {
System.out.println("请选择需要操作的文件夹");
foreachFolder = PublicWays.selectSavePath(txtFile);//当为空或仅执行当前类时拉起选择需要遍历的文件夹
}
init();
}
private static void init() {
/*创建日志文本文件*/
String txtName = "Log.txt";
String savePath = "";
txtFile = new File(savePath + txtName);
PublicWays.creatFile(txtFile);
PublicWays.modifyFileContents(txtFile, "\n" + PublicWays.getCurrentTime("yyyy-MM-dd HH:mm:ss") + "\n\n", false);
FileUtils fileUtils = FileUtils.getInstance();
File file = new File(foreachFolder);
File[] files = file.listFiles();
assert files != null;
System.out.println("文件夹内文件数量:" + files.length);
long startTime, endTime;
startTime = System.currentTimeMillis();
ArrayList<int[]> filesList = new ArrayList<>();
for (File f : files) {
filesList.add(getData(f));
}
ArrayList<File> duplicateFileList = new ArrayList<>();
endTime = System.currentTimeMillis();
System.out.println("转化二进制添加至数组耗时: " + (endTime - startTime) + "ms");
compare(filesList, files, duplicateFileList);//开始遍历
delete(duplicateFileList, fileUtils);//开始删除重复文件
endTime = System.currentTimeMillis();
System.out.println("总耗时: " + (endTime - startTime) + "ms");
}
static BufferedImage img, slt;
/**
* 将图片转成二进制
*
* @param file 需要转存的图片
* @return 返回二进制数组
*/
public static int[] getData(File file) {
try {
img = ImageIO.read(file);
slt = new BufferedImage(100, 100,
BufferedImage.TYPE_INT_RGB);
slt.getGraphics().drawImage(img, 0, 0, 100, 100, null);
int[] data = new int[256];
int r, g, b, rgb, x, y;//避免重复定义,循环前先全部定义完
Color myColor;
for (x = 0; x < slt.getWidth(); x++) {
for (y = 0; y < slt.getHeight(); y++) {
rgb = slt.getRGB(x, y);
myColor = new Color(rgb);
r = myColor.getRed();
g = myColor.getGreen();
b = myColor.getBlue();
data[(r + g + b) / 3]++;
}
}
return data;
} catch (Exception exception) {
System.out.println("出错啦!");
return null;
}
}
/**
* 对比两张图片的相似度
*
* @param s 第一张图
* @param t 第二张图
* @return 返回相似度
*/
public static float compare(int[] s, int[] t) {
try {
float result = 2F;
int i, abs, max;
assert s != null;
assert t != null;
for (i = 0; i < 256; i++) {
abs = Math.abs(s[i] - t[i]);
max = Math.max(s[i], t[i]);
result += (1 - ((float) abs / (max == 0 ? 1 : max)));
}
return (result / 256) * 100;
} catch (Exception exception) {
return 0;
}
}
/**
* 遍历数组,开始对比相似度
*
* @param filesList 需要对比相似度文件夹对应转存的二进制数组
* @param files 需要对比相似度文件夹
* @param duplicateFiles 用于存储重复的图片数组
*/
private static void compare(ArrayList<int[]> filesList, File[] files, ArrayList<File> duplicateFiles) {
long startTime, endTime;
startTime = System.currentTimeMillis();
float percent;
int num = 0, i, j;
for (i = 4; i < filesList.size(); i++) {
if (files[i].exists()) {
for (j = i + 1; j < filesList.size(); j++) {
percent = compare(filesList.get(i), filesList.get(j));
if (percent >= 90 && files[j].exists()) {
duplicateFiles.add(files[j]);
}
num++;
}
} else
System.out.println(files[i] + " is not exit!");
}
endTime = System.currentTimeMillis();
System.out.println("对比图片耗时: " + (endTime - startTime) + "ms");
PublicWays.modifyFileContents(txtFile, "对比图片" + num + "次, 共耗时: " + (endTime - startTime) + "ms" + "\n", true);
}
/**
* 删除重复图片
*
* @param duplicateFileList 需要删除的重复图片数组
* @param fileUtils 为避免误操作,用于将图片扔至回收站
*/
private static void delete(ArrayList<File> duplicateFileList, FileUtils fileUtils) {
long startTime, endTime;
startTime = System.currentTimeMillis();
try {
for (File f : duplicateFileList) {
if (f.exists()) {
fileUtils.moveToTrash(new File[]{f});
PublicWays.modifyFileContents(txtFile, " 删除图片 " + f.getName(), true);
}
}
} catch (IOException ignored) {
}
endTime = System.currentTimeMillis();
System.out.println("删除图片耗时: " + (endTime - startTime) + "ms");
PublicWays.modifyFileContents(txtFile, "删除" + duplicateFileList.size() + "张图片, 共耗时: " + (endTime - startTime) + "ms" + "\n", true);
}
public static void main(String[] args) {
new DeleteDuplicateImg(null, null);
}
}
PublicWays类:
/**
* 修改指定文件的内容
* --分割线--
* FileWriter第二个参数true意为续写,false或不写则为覆盖
*
* @param file 需要修改内容的文件
* @param info 修改的内容
* @param isAppend 选择是覆写还是续写,true为续写,false为覆写
*/
public static void modifyFileContents(File file, String info, Boolean isAppend) {
try {
FileWriter fileWriter = new FileWriter(file, isAppend);
fileWriter.write(info);
fileWriter.flush();
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("写入指定" + file.getName().substring(file.getName().lastIndexOf(".") + 1) + "文件内容出错:" + e.getMessage());
}
}
/**
* 获取当前时间并自定义格式化
*
* @param format 自定义格式化格式(yyyy:年 MM:月 dd:日 HH:时 mm:分 ss:秒)
*/
public static String getCurrentTime(String format) {
return new SimpleDateFormat(format).format(new Date());
}
/**
* 在指定路径创建指定文件
*
* @param file 需要创建的txt文件
*/
public static void creatFile(File file) {
if (!file.exists()) {
try {
file.createNewFile();
System.out.println("创建指定" + file.getName().substring(file.getName().lastIndexOf(".") + 1) + "文本文件成功!");
} catch (IOException e) {
e.printStackTrace();
System.out.println("创建指定" + file.getName().substring(file.getName().lastIndexOf(".") + 1) + "文本文件出错:" + e.getMessage());
}
} else {
System.out.println("指定" + file.getName().substring(file.getName().lastIndexOf(".") + 1) + "文本文件已存在!");
}
}