我有一個包含相同照片但名稱不同的檔案夾,我想使用我相當新的 Stream API 洗掉重復項(不管是哪個)。
我嘗試使用這種方法,但當然不是那么簡單,它只是洗掉所有檔案。
File directory = new File("D:\\Photos\\Test");
List<File> files = Arrays.asList(Objects.requireNonNull(directory.listFiles()));
files.stream().distinct().forEach(file -> Files.delete(file.toPath()));
我還嘗試將每個檔案轉換為位元組陣列并應用于位元組陣列distinct()流,但沒有找到任何重復項。
有沒有辦法通過只使用流來實作這一點?
uj5u.com熱心網友回復:
但當然不是那么簡單,它只是洗掉所有檔案
當然,distinct()在File物件流中會保留具有不同路徑的流檔案(因為equals()檔案不關心內容,它會比較路徑),并且由于所有檔案都有不同的路徑,因此它們都會被洗掉。
您真正需要的是確定兩個檔案內容Files.mismatch()相同的邏輯,并且從 Java 12 開始,我們擁有指定檔案的方法位元組并回傳不匹配的第一個索引,或者-1它們是否相同。
另一個需要注意的重要事情是,在這種情況下,Stream IPA不是正確的工具,因為需要處理檢查的例外。mismatch()和delete()throw IOException(這對于類中的方法很常見)Files,我們不能將它傳播到流之外。lambda 中的例外處理邏輯看起來很難看,完全破壞了可讀性。mismatch()您可以選擇將呼叫和的代碼提取delete()到兩個單獨的方法中,但這會導致例外處理邏輯的重復。
更好的選擇是DirectoryStream用作遍歷的手段,并在現場處理例外:
public static void removeDuplicates(Path targetFolder, Path originalFile) {
try(DirectoryStream<Path> paths = Files.newDirectoryStream(targetFolder)) {
for (Path path: paths) {
if (Files.mismatch(path, originalFile) == -1
&& !originalFile.equals(path)) { // files match & file isn't the original one
Files.delete(path);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
旁注: File類是遺留的,避免使用它。堅持使用PathandFiles代替。
如果沒有特定的原始檔案,并且您需要對檔案夾中的重復檔案進行分析和清理,您可以對檔案夾中的每個檔案觸發上述方法。但這會導致多次讀取相同的檔案,這是不希望的。
為了避免多次讀取檔案,我們可以計算每個遇到的檔案的哈希值,并將每個哈希值提供給Set. 如果哈希被拒絕,則意味著該檔案是重復的。
在下面的代碼中,SHA-256 用作散列演算法。
public static void removeDuplicates(Path targetFolder) {
try (DirectoryStream<Path> paths = Files.newDirectoryStream(targetFolder)) {
Set<String> seen = new HashSet<>();
for (Path path : paths) {
if (Files.isDirectory(path)) continue;
if (!seen.add(getHash(path))) { // hash sum has been encountered previously - hence the fail is a duplicate
Files.delete(path);
}
}
} catch (IOException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static String getHash(Path path) throws NoSuchAlgorithmException, IOException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(Files.readAllBytes(path));
return toHexadecimal(md.digest());
}
public static String toHexadecimal(byte[] bytes) {
return IntStream.range(0, bytes.length)
.mapToObj(i -> String.format("x", bytes[i]))
.collect(Collectors.joining());
}
請注意,雖然兩個不同的檔案可能會產生相同的哈希值,但這是極不可能的。上面顯示的代碼忽略了碰撞的可能性。
如果您想知道可以處理沖突的代碼是什么樣的,這里有一個擴展版本。
uj5u.com熱心網友回復:
前段時間我做了一個比較兩個影像并檢查影像是否重復的android應用程式,所以我遇到了同樣的問題,經過一段時間的搜索,我在StackOverflow上找到了答案,但目前我沒有已保存答案鏈接,因此我正在共享代碼,也許它會給您一些想法或幫助。
public class Main {
public static void main(String[] args) throws IOException {
ImageChecker i = new ImageChecker();
BufferedImage one = ImageIO.read(new File("img1.jpg"));
BufferedImage two = ImageIO.read(new File("img2.jpg"));
if(one.getWidth() one.getHeight() >= two.getWidth() two.getHeight()) {
i.setOne(one);
i.setTwo(two);
} else {
i.setOne(two);
i.setTwo(one);
}
System.out.println(i.compareImages());
}
}
public class ImageChecker {
private BufferedImage one;
private BufferedImage two;
private double difference = 0;
private int x = 0;
private int y = 0;
public ImageChecker() {
}
public boolean compareImages() {
int f = 20;
int w1 = Math.min(50, one.getWidth() - two.getWidth());
int h1 = Math.min(50, one.getHeight() - two.getHeight());
int w2 = Math.min(5, one.getWidth() - two.getWidth());
int h2 = Math.min(5, one.getHeight() - two.getHeight());
for (int i = 0; i <= one.getWidth() - two.getWidth(); i = f) {
for (int j = 0; j <= one.getHeight() - two.getHeight(); j = f) {
compareSubset(i, j, f);
}
}
one = one.getSubimage(Math.max(0, x - w1), Math.max(0, y - h1),
Math.min(two.getWidth() w1, one.getWidth() - x w1),
Math.min(two.getHeight() h1, one.getHeight() - y h1));
x = 0;
y = 0;
difference = 0;
f = 5;
for (int i = 0; i <= one.getWidth() - two.getWidth(); i = f) {
for (int j = 0; j <= one.getHeight() - two.getHeight(); j = f) {
compareSubset(i, j, f);
}
}
one = one.getSubimage(Math.max(0, x - w2), Math.max(0, y - h2),
Math.min(two.getWidth() w2, one.getWidth() - x w2),
Math.min(two.getHeight() h2, one.getHeight() - y h2));
f = 1;
for (int i = 0; i <= one.getWidth() - two.getWidth(); i = f) {
for (int j = 0; j <= one.getHeight() - two.getHeight(); j = f) {
compareSubset(i, j, f);
}
}
System.out.println(difference);
return difference < 0.1;
}
public void compareSubset(int a, int b, int f) {
double diff = 0;
for (int i = 0; i < two.getWidth(); i = f) {
for (int j = 0; j < two.getHeight(); j = f) {
int onepx = one.getRGB(i a, j b);
int twopx = two.getRGB(i, j);
int r1 = (onepx >> 16);
int g1 = (onepx >> 8) & 0xff;
int b1 = (onepx) & 0xff;
int r2 = (twopx >> 16);
int g2 = (twopx >> 8) & 0xff;
int b2 = (twopx) & 0xff;
diff = (Math.abs(r1 - r2) Math.abs(g1 - g2) Math.abs(b1
- b2)) / 3.0 / 255.0;
}
}
double percentDiff = diff * f * f / (two.getWidth() * two.getHeight());
if (percentDiff < difference || difference == 0) {
difference = percentDiff;
x = a;
y = b;
}
}
public BufferedImage getOne() {
return one;
}
public void setOne(BufferedImage one) {
this.one = one;
}
public BufferedImage getTwo() {
return two;
}
public void setTwo(BufferedImage two) {
this.two = two;
}
}
此代碼首先比較影像的高度和寬度,因為影像可能具有不同的大小,然后,它使用 RGB 代碼逐像素比較它們并回傳結果。
注意:- 所有代碼都歸原作者所有,但我不記得名字了,所以如果你是作者,請告訴我,我會更新你的名字并回答鏈接。
uj5u.com熱心網友回復:
試試這個。您可以進行清理,但我認為這對您有用。我從這個鏈接中獲取了參考。
如何使用java比較影像的相似性
public class FileCompare {
public static void main(String[] args) {
File directory = new File("D:\\Photos\\Test");
List<File> filesToBeDeleted = new ArrayList<>();
List<File> files = Arrays.asList(Objects.requireNonNull(directory.listFiles()));
IntStream.range(0, files.size() - 1).forEach(i -> {
boolean bool = compareImage(files.get(i), files.get(i 1));
if (bool) {
filesToBeDeleted.add(files.get(i 1));
}
});
filesToBeDeleted.stream().forEach(file -> {
try {
Files.delete(file.toPath());
} catch (IOException e) {
e.printStackTrace();
}
});
}
public static boolean compareImage(File fileA, File fileB) {
try {
BufferedImage biA = ImageIO.read(fileA);
DataBuffer dbA = biA.getData().getDataBuffer();
int sizeA = dbA.getSize();
BufferedImage biB = ImageIO.read(fileB);
DataBuffer dbB = biB.getData().getDataBuffer();
int sizeB = dbB.getSize();
if (sizeA == sizeB) {
for (int i = 0; i < sizeA; i ) {
if (dbA.getElem(i) != dbB.getElem(i)) {
return false;
}
}
return true;
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/505067.html
