亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Java:如何不僅按名稱而且按大小和內容搜索文件夾中的重復文件?

Java:如何不僅按名稱而且按大小和內容搜索文件夾中的重復文件?

慕斯王 2023-03-02 15:14:08
我想創建一個 Java 應用程序來識別重復項。到目前為止,我只能通過名稱找到重復項,但我還需要大小、文件類型,也許還需要內容。到目前為止,這是我的代碼,使用HashMap:public static void find(Map<String, List<String>> lists, File dir) {    for (File f : dir.listFiles()) {        if (f.isDirectory()) {            find(lists, f);        } else {            String hash = f.getName() + f.length();            List<String> list = lists.get(hash);            if (list == null) {                list = new LinkedList<String>();                lists.put(hash, list);            }            list.add(f.getAbsolutePath());        }    }}
查看完整描述

4 回答

?
白衣染霜花

TA貢獻1796條經驗 獲得超10個贊

我使用 MessageDigest 并檢查了一些文件,并根據我在標題和描述中列出的所有標準找到了重復項。謝謝你們。


private static MessageDigest messageDigest;

static {

    try {

        messageDigest = MessageDigest.getInstance("SHA-512");

    } catch (NoSuchAlgorithmException e) {

        throw new RuntimeException("cannot initialize SHA-512 hash function", e);

    }

}   

這是在重復搜索代碼中實現后的結果


public static void find(Map<String, List<String>> lists, File dir) {

for (File f : dir.listFiles()) {

  if (f.isDirectory()) {

    find(lists, f);

  } else {

      try{

          FileInputStream fi = new FileInputStream(f);

          byte fileData[] = new byte[(int) f.length()];

                fi.read(fileData);

                fi.close();

                //Crearea id unic hash pentru fisierul curent

                String hash = new BigInteger(1, messageDigest.digest(fileData)).toString(16);

                List<String> list = lists.get(hash);

                if (list == null) {

                    list = new LinkedList<String>();

                }

                //Ad?uga?i calea c?tre list?

                list.add(f.getAbsolutePath());

                //Adauga lista actualizat? la tabelul Hash

                lists.put(hash, list);


      }catch (IOException e) {

                throw new RuntimeException("cannot read file " + f.getAbsolutePath(), e);

            }


  }

}

}


查看完整回答
反對 回復 2023-03-02
?
動漫人物

TA貢獻1815條經驗 獲得超10個贊

如果 2 個文件具有相同的擴展名和相同的文件大小,則認為它們相等,這只是創建一個代表這種“平等”的對象的問題。所以,你會做這樣的事情:


public class FileEquality {

    private final String fileExtension;

    private final long fileSize;


    // constructor, toString, equals, hashCode, and getters here.

}

(并填寫所有缺失的樣板文件:Constructor、toString、equals、hashCode 和 getter。如果您愿意,請參閱Project Lombok 的 @Value以簡化此操作)。fileName.lastIndexOf('.')您可以使用和從文件名獲取文件擴展名fileName.substring(lastIndex)。使用 lombok,您只需編寫:


@lombok.Value public class FileEquality {

    String fileExtension;

    long fileSize;

}

然后使用FileEquality對象作為哈希圖中的鍵而不是字符串。但是,僅僅因為你有,比如說,'foo.txt' 和 'bar.txt' 兩者的大小恰好都是 500 字節并不意味著這 2 個文件是重復的。所以,你也想要涉及內容,但是,如果你擴展你的FileEquality類以包含文件的內容,那么會出現兩件事:

  1. 如果您無論如何都要檢查內容,大小和文件擴展名有什么關系?foo.txt如果和的內容bar.jpg完全相同,那么它們就是重復的,不是嗎?何必。您可以將內容傳達為 a byte[],但請注意,編寫適當的hashCode()equals()實現(如果您想將此對象用作哈希映射的鍵,則需要這樣做)變得有點棘手。幸運的是,lombok@Value會做對,所以我建議你使用它。

  2. 這意味著整個文件內容都在 JVM 的進程內存中。除非您正在檢查非常小的文件,否則您將耗盡內存。您可以通過不存儲文件的全部內容,而是存儲內容的散列來稍微抽象一下。Google 關于如何計算 java 文件的 sha-256 散列。將此哈希值放入您的中FileEquality,現在您可以避免內存問題。理論上可能有 2 個文件具有不同的內容,但它們哈希到完全相同的 sha-256 值,但這種情況的可能性是天文數字,更重要的是,sha-256 的設計使得故意在數學上不可行制作 2 個這樣的文件來擾亂您的應用程序。因此,我建議您只信任哈希 :)

當然,請注意,散列整個文件需要讀取整個文件,因此如果您在包含 500GB 文件的目錄上運行重復查找器,那么您的應用程序將至少需要讀取 500GB,這將花一些時間。


查看完整回答
反對 回復 2023-03-02
?
偶然的你

TA貢獻1841條經驗 獲得超3個贊

我很久以前就做了這個應用程序,如果你想學習的話,我找到了它的一些源代碼。


此方法通過比較兩個文件字節來工作。


public static boolean checkBinaryEquality(File file1, File file2) {

    if(file1.length() != file2.length()) return false;

    try(FileInputStream f1 = new FileInputStream(file1); FileInputStream f2 = new FileInputStream(file2)){

            byte bus1[] = new byte[1024],

                 bus2[] = new byte[1024];

            // comparing files bytes one by one if we found unmatched results that means they are not equal

            while((f1.read(bus1)) >= 0) {

                f2.read(bus2);

                for(int i = 0; i < 1024;i++)

                    if(bus1[i] != bus2[i]) 

                        return false;

            }

            // passed

            return true;

    } catch (IOException exp) {

        // problems occurred so let's consider them not equal

        return false;

    }

}

將此方法與名稱和擴展名檢查結合起來,您就可以開始了。


查看完整回答
反對 回復 2023-03-02
?
慕碼人8056858

TA貢獻1803條經驗 獲得超6個贊

復制粘貼示例


創建一個擴展類File


import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.util.Arrays;


public class MyFile extends File {

    private static final long serialVersionUID = 1L;


    public MyFile(final String pathname) {

        super(pathname);

    }


    @Override

    public boolean equals(final Object obj) {

        if (this == obj) {

            return true;

        }

        if (this.getClass() != obj.getClass()) {

            return false;

        }

        final MyFile other = (MyFile) obj;

        if (!Arrays.equals(this.getContent(), other.getContent())) {

            return false;

        }

        if (this.getName() == null) {

            if (other.getName() != null) {

                return false;

            }

        } else if (!this.getName().equals(other.getName())) {

            return false;

        }

        if (this.length() != other.length()) {

            return false;

        }

        return true;

    }


    @Override

    public int hashCode() {

        final int prime = 31;

        int result = prime;

        result = (prime * result) + Arrays.hashCode(this.getContent());

        result = (prime * result) + ((this.getName() == null) ? 0 : this.getName().hashCode());

        result = (prime * result) + (int) (this.length() ^ (this.length() >>> 32));

        return result;

    }


    private byte[] getContent() {

        try (final FileInputStream fis = new FileInputStream(this)) {

            return fis.readAllBytes();

        } catch (final IOException e) {

            e.printStackTrace();

            return new byte[] {};

        }

    }

}

讀取基本目錄


import java.io.File;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import java.util.Map.Entry;

import java.util.Vector;


public class FileTest {

    public FileTest() {

        super();

    }


    public static void main(final String[] args) {

        final Map<MyFile, List<MyFile>> duplicates = new HashMap<>();

        FileTest.handleDirectory(duplicates, new File("[path to base directory]"));

        final Iterator<Entry<MyFile, List<MyFile>>> iterator = duplicates.entrySet().iterator();

        while (iterator.hasNext()) {

            final Entry<MyFile, List<MyFile>> next = iterator.next();

            if (next.getValue().size() == 0) {

                iterator.remove();

            } else {

                System.out.println(next.getKey().getName() + " - " + next.getKey().getAbsolutePath());

                for (final MyFile file : next.getValue()) {

                    System.out.println("        ->" + file.getName() + " - " + file.getAbsolutePath());

                }

            }

        }

    }


    private static void handleDirectory(final Map<MyFile, List<MyFile>> duplicates, final File directory) {

        final File dir = directory;

        if (dir.isDirectory()) {

            final File[] files = dir.listFiles();

            for (final File file : files) {

                if (file.isDirectory()) {

                    FileTest.handleDirectory(duplicates, file);

                    continue;

                }

                final MyFile myFile = new MyFile(file.getAbsolutePath());

                if (!duplicates.containsKey(myFile)) {

                    duplicates.put(myFile, new Vector<>());

                } else {

                    duplicates.get(myFile).add(myFile);

                }

            }

        }

    }

}


查看完整回答
反對 回復 2023-03-02
  • 4 回答
  • 0 關注
  • 153 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號