2012-11-03 8 views
6

Pracuję nad programem, który (mam nadzieję) porówna wszystkie pliki w danym katalogu, zidentyfikuje duplikaty, doda je do listy, a następnie wyświetli listę do użytkownika, aby mogli sprawdzić, czy chcą usunąć te pliki przed ich usunięciem i jestem poważnie zablokowany. Do tej pory udało mi się rekurencyjnie wyliczyć wszystkie pliki i próbowałem ich porównywać, aby znaleźć duplikaty. Szybko zdaję sobie sprawę, że aby osiągnąć to, czego chcę, będę musiał porównać więcej niż jeden atrybut pliku. Nie wszystkie pliki będą plikami tekstowymi, a porównywanie tekstu jest w większości tym, co znalazłem, o ile kod przykładowy w Internecie idzie, próbuję dowiedzieć się więcej o danych binarnych, ponieważ porównywanie tablic bajtów i nazw plików jest najlepsze, na co mogłem przyjść z. W szczególności pytam, które atrybuty najlepiej porównać, aby zrównoważyć dokładność znajdowania duplikatów i być w stanie obsłużyć katalog o rozsądnej wielkości? A jeśli nie masz nic przeciwko, w jaki sposób mogę zaimplementować to w moim kodzie? Mam nadzieję, że moje pytanie nie było zbyt straszne, naprawdę doceniam każdą pomoc, jaką mogę uzyskać. Oto, co mam, i tak, kilka metod i drugi plik, który znalazłem tutaj, na wypadek gdybyś się zastanawiał. P.S. Naprawdę mi przykro z powodu zmiennych bezsensowne, jeśli brakowało mi każdy, próbowałem oczyścić kod trochę przed wysłaniem goPotrzebuję pomocy w porównywaniu plików w katalogu rekursywnie, aby znaleźć duplikaty.

ListFilesInDir.java

import java.io.*; 
import java.nio.file.Files; 
import java.nio.file.attribute.*; 
import java.security.*; 
import java.util.*; 

public final class ListFilesInDir { 

static File startingDir; 

static List<File> files; 
static List<File> dirs; 
static TreeMap<Integer, File> duplicates; 
static ArrayList<Integer> usedIndexes = new ArrayList<Integer>(); 
static ArrayList<File> duplicateList = new ArrayList<File>(); 

static File out = new File("ListDuplicateFiles.txt"); 
static PrintWriter output; 

static int key = 0; 
static String tabString; 
static TreeMap<Integer, File> tMap = new TreeMap<Integer, File>(); 

static int num1 = 0; 
static int num2 = 0; 
static File value1 = null; 
static File value2 = null; 
static String path1 = null; 
static String name1 = null; 
static String path2 = null; 
static String name2 = null; 

public static void main(String[] args) throws FileNotFoundException { 
    new ListFilesInDir(args[0]); 
} 

public ListFilesInDir(String string) throws FileNotFoundException { 
    startingDir = new File(string); 
    dirs = new ArrayList<File>(); 
    duplicates = new TreeMap<Integer, File>(); 
    output = new PrintWriter(out); 

    getFiles(startingDir); 
    compareFiles(); 
    writeDuplicateList(); 
} 

public void getFiles(File root) throws FileNotFoundException { 
    System.out.println("Adding files to list..."); 
    ListFilesInDir.files = getFileList(root); 
    for (File file : files) { 
     if (!file.isFile()) { 
      System.out.println("Adding DIR: " + key + " name: " + file); 
      dirs.add(file); 
     } else { 
      System.out.println("Adding FILE: " + key + " name: " + file); 
      tMap.put(key, file); 
     } 
     key++; 
    } 
    System.out.println(dirs.size()); 
    System.out.println("Complete"); 
} 

public static void compareFiles() throws FileNotFoundException { 
    System.out.println("Preparing to compare files..."); 
    for (num1 = 0; num1 < files.size(); num1++) { 
     for (num2 = 0; num2 < files.size(); num2++) { 

      if (num1 != num2) { 
       value1 = files.get(num1); 
       value2 = files.get(num2); 
       path1 = value1.getAbsolutePath(); 
       path2 = value2.getAbsolutePath(); 
       name1 = path1.substring(path1.lastIndexOf(File.separator)); 
       name2 = path2.substring(path2.lastIndexOf(File.separator)); 
       HashMap<Integer, File> testMap = new HashMap<Integer, File>(); 

       System.out.println(num1 + "|" + num2 + " : " + value1 
         + " - " + value2); 
       if (CompareBinaries.fileContentsEquals(
         value1.getAbsolutePath(), value2.getAbsolutePath()) == true) { 
        if (testMap.put(num1, value1) != null) { 
         TreeSet<File> fileTreeSet; 
        } 
        addDuplicate(num1, value1); 
        files.remove(num1); 

        System.out.println("added(binary): " + num1 + ":" 
          + value1); 

       } else if (value1.getName().equalsIgnoreCase(
         value2.getName())) { 
        addDuplicate(num1, value1); 
        files.remove(num1); 
        System.out.println("added(name): " + num1 + ":" 
          + value1); 
       } 
      } 
     } 
    } 
    System.out.println("Complete"); 

} 

public static void writeDuplicateList() { 
    int printKey = 0; 
    for (File file : duplicateList) { 
     output.printf("%03d | %s\n", printKey, file); 
     System.out.printf("%03d | %s\n", printKey, file); 
     printKey++; 
    } 

    output.append(docsInfo()); 
    output.close(); 
    output.flush(); 

    System.out.println("\n"+files.size()+" files in "+startingDir.getAbsolutePath() +", "+duplicateList.size()+" duplicate files."); 
} 

static public String docsInfo() { 
    String s = "\n\n" + files.size() + " files in " 
      + startingDir.getAbsolutePath() + ", " + duplicates.size() 
      + " duplicate files."; 
    return s; 
} 

static public List<File> getFileList(File file) 
     throws FileNotFoundException { 
    List<File> result = getUnsortedFileList(file); 
    Collections.sort(result); 
    return result; 
} 

static private List<File> getUnsortedFileList(File file) 
     throws FileNotFoundException { 
    List<File> result = new ArrayList<File>(); 
    File[] filesAndDirs = file.listFiles(); 
    List<File> filesDirs = Arrays.asList(filesAndDirs); 
    int dirKey = 0; 

    for (File fileList : filesDirs) { 
     result.add(fileList); 
     if (!fileList.isFile()) { 

      List<File> deeperList = getUnsortedFileList(fileList); 
      result.addAll(deeperList); 
     } 
    } 
    return result; 
    } 

     static private void validateDir(File dir) throws FileNotFoundException { 
    if (dir == null) 
     throw new IllegalArgumentException("Directory is null!"); 
    if (!dir.exists()) 
     throw new FileNotFoundException("Directory doesn't exist: " + dir); 
    if (!dir.isDirectory()) 
     throw new IllegalArgumentException(dir + "is not a directory!"); 
    if (!dir.canRead()) 
     throw new IllegalArgumentException("Directory cannot be read: " 
       + dir); 
    } 

     public static void addDuplicate(int i, File file)throws FileNotFoundException{ 
      if (!duplicates.containsKey(i)) { 
      duplicates.put(i, file); 
       duplicateList.add(file); 

      } 
    } 
    } 

CompareBinaries.java

import java.io.File; 
import java.io.FileInputStream; 
import java.io.InputStream; 
import java.util.Arrays; 


public class CompareBinaries { 

private final static int BUFFSIZE = 1024; 
private static byte buff1[] = new byte[BUFFSIZE]; 
private static byte buff2[] = new byte[BUFFSIZE]; 

public static boolean inputStreamEquals(InputStream is1, InputStream is2) { 
    if(is1 == is2) return true; 

    if(is1 == null && is2 == null) { 
     System.out.println("both input streams are null"); 
     return true; 
    } 

    if(is1 == null || is2 == null) return false; 
    try { 
     int read1 = -1; 
     int read2 = -1; 

     do { 
      int offset1 = 0; 
      while (offset1 < BUFFSIZE 
         && (read1 = is1.read(buff1, offset1, BUFFSIZE-offset1)) >= 0) { 
         offset1 += read1; 
       } 

      int offset2 = 0; 
      while (offset2 < BUFFSIZE 
         && (read2 = is2.read(buff2, offset2, BUFFSIZE-offset2)) >= 0) { 
         offset2 += read2; 
       } 
      if(offset1 != offset2) return false; 
      if(offset1 != BUFFSIZE) { 
       Arrays.fill(buff1, offset1, BUFFSIZE, (byte)0); 
       Arrays.fill(buff2, offset2, BUFFSIZE, (byte)0); 
      } 
      if(!Arrays.equals(buff1, buff2)) return false; 
     } while(read1 >= 0 && read2 >= 0); 
     if(read1 < 0 && read2 < 0) return true; // both at EOF 
     return false; 

    } catch (Exception ei) { 
     return false; 
    } 
} 

public static boolean fileContentsEquals(File file1, File file2) { 
    InputStream is1 = null; 
    InputStream is2 = null; 
    if(file1.length() != file2.length()) return false; 

    try { 
     is1 = new FileInputStream(file1); 
     is2 = new FileInputStream(file2); 

     return inputStreamEquals(is1, is2); 

    } catch (Exception ei) { 
     return false; 
    } finally { 
     try { 
      if(is1 != null) is1.close(); 
      if(is2 != null) is2.close(); 
     } catch (Exception ei2) {} 
    } 
} 

public static boolean fileContentsEquals(String fn1, String fn2) { 
    return fileContentsEquals(new File(fn1), new File(fn2)); 
} 

}

+0

"A jeśli to nie przeszkadza, jak mogłaby wdrożyć go w moim kodzie" = plz wysłać teh codez – Raedwald

Odpowiedz

2

Do porównania dwóch plików można użyć funkcji skrótu - dwa pliki (w innym folderze) mogą mieć tę samą nazwę i atrybuty (np. Długość), ale inną treść. Na przykład możesz utworzyć plik tekstowy, a następnie skopiować go do innego folderu, zmieniając jedną literę w treści.

Funkcja mieszająca wykonuje sprytne obliczenia matematyczne na zawartości pliku kończąc na numerze, nawet niewielka różnica w zawartości kończy się na dwóch bardzo różnych liczbach.

Przyjmując na przykład funkcję skrótu md5, tworzy ona 16 bajtów z tablicy bajtów o dowolnej długości. Chociaż teoretycznie możliwe jest utworzenie dwóch plików z tą samą wartością md5, ale inną treścią, prawdopodobieństwo jest bardzo niskie (podczas gdy dwa pliki o tej samej nazwie i rozmiarze, ale inna treść jest zdarzeniem o stosunkowo dużym prawdopodobieństwie):

Chodzi o to, że może zbudować tabelę md5 zawartości pliku, to musi być obliczone tylko raz i jest szybkie do porównania - jeśli md5 są różne, pliki są różne ze 100% pewnością. Tylko w mało prawdopodobnym przypadku, gdy md5 będzie taki sam, będziesz musiał uciekać się do porównania bajt po bajcie, aby być w 100% pewnym.

+0

myślałem md5 był tylko szyfrowanie algorytm, ale to brzmi genialnie. Czy jest jakaś szansa, że ​​możesz polecić książkę lub poznać miejsce w sieci, w którym mogłem dowiedzieć się więcej? Mam na myśli coś innego niż API, oczywiście, że sprawdzę to. Obawiałem się porównywania bajtów plików dla bajtu i czasu, jaki może zająć, ale to może być rzeczywiście możliwe, jeśli funkcja md5 zwróci wystarczająco małą listę duplikatów. Wielkie dzięki, naprawdę doceniam twoją pomoc. –

+0

Hashing jest często używany w kryptografii, jednak istnieje wiele innych zastosowań - spójrz na http://en.wikipedia.org/wiki/Hash_function – thedayofcondor

+0

W szczególności, jeśli używasz java, klasa Object ma istotną metodę W większości przypadków MUSISZ przesłonić: http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode zobacz także: http://en.wikipedia.org/wiki/Java_hashCode – thedayofcondor

1

Moja sugestia: Przejdź przez jedno drzewo katalogów, porównaj z innym drzewem katalogów według nazwy. Następnie dla każdej pasującej pary porównaj rozmiar pliku i czas ostatniej modyfikacji, a jeśli wszystko jest równe, wykonaj proste porównanie bajt po bajcie.

Są tam dwa kroki w celu wdrożenia tego (jeżeli są dodane linki do przykładu kod):

  1. chodzić po obu katalogach, aby uzyskać pełną listę. Java przyspieszyła to dzięki Java 7 i Files.walkFileTree(). Przechodzisz przez jedno drzewo katalogów i porównujesz każdy wpis z innym drzewem katalogów. Wysłałem here przykładowy kod do takiego porównania (Mój przykładowy kod powinien ci pomóc w tym kroku, ale nie trafia 100% twojego pytania)
  2. Porównaj dwa pliki, jeśli są równe lub nie. Kilka rzeczy można porównać:
    • Nazwa pliku. Jest to oczywiste, ponieważ i tak trzeba znaleźć plik w drugim drzewie.
    • Rozmiar pliku, czas ostatniej modyfikacji: Są częścią BasicFileAttributes, którą otrzymujesz podczas chodzenia po drzewie. Zobacz przykładowy kod, jak zdobyć go dla drugiego pliku.
    • Zawartość. Jak wspomniano powyżej, możesz obliczyć rodzaj crc, md5, sha. Co się stanie, to, że przeczytasz pełną zawartość obu plików. Tak więc moja sugestia polega na bezpośrednim porównywaniu bajt po bajcie, np. z [Arrays.equals()] (http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#equals(byte[], byte []))
Powiązane problemy