2012-01-19 14 views
19

Nie wiem jak wy, ale przynajmniej spodziewałem się, że f1 będzie równe f2 w poniższym kodzie, ale najwyraźniej tak nie jest! Jakie są twoje myśli na ten temat? Wygląda na to, że muszę napisać własną metodę równości, żeby ją wspierać, prawda?Plik Java jest równy

import java.io.*; 

public class FileEquals 
{ 
    public static void main(String[] args) 
    { 
     File f1 = new File("./hello.txt"); 
     File f2 = new File("hello.txt"); 
     System.out.println("f1: " + f1.getName()); 
     System.out.println("f2: " + f2.getName()); 
     System.out.println("f1.equals(f2) returns " + f1.equals(f2)); 
     System.out.println("f1.compareTo(f2) returns " + f1.compareTo(f2)); 
    } 
} 
+1

To samo dzieje się z klasą ścieżki Java 7. Istnieją jednak metody takie jak Path.normalize() lub Files.isSameFile() – Luciano

+0

Możesz bezpiecznie zabezpieczyć wszystkich użytkowników tego pytania w pewnym momencie, pokazując rzeczywiste wyniki. Spodziewałem się, że 'equals' i' compareTo' mają sprzeczne wyniki. Tak nie jest, "equals" zwraca false, a 'compareTo' zwraca -58, co oznacza leksykograficznie" mniej niż ". @Luciano: Zauważ, że 'Files.isSameFile' w tym przypadku spróbuje otworzyć pliki, ponieważ ścieżki nie są równe i mogą zawieść z' NoSuchFileException'. – bluenote10

Odpowiedz

30

Nie, tak nie jest. Ponieważ równa jest porównanie równości ścieżek bezwzględnych (w przypadku ponad nim jest coś takiego jak:.

some-project\.\hello.txt 
some-project\hello.txt 

Więc są one naturalnie inna

Wydaje się, że muszę napisać własny równa metody aby ją wspierać, prawo?

Pewnie tak. Ale przede wszystkim trzeba wiedzieć, co chcesz porównać? Tylko ścieżek? Jeśli tak, to porównać swoją kanoniczną ścieżkę w ten sposób:

f1.getCanonicalPath().equals(f2.getCanonicalPath()) 

Ale jeśli chcesz porównać zawartość dwóch plików, a następnie yes, należy napisać swój własny sposób - lub po prostu skopiować gdzieś w internecie.

Pozdrowienia

+1

Naprawdę chcę zrobić coś w stylu "fileList.zawiera (plik) "i ta metoda wywołuje metodę equals. – aandeers

1

Oto realizacja obu metod:

/** 
* Tests this abstract pathname for equality with the given object. 
* Returns <code>true</code> if and only if the argument is not 
* <code>null</code> and is an abstract pathname that denotes the same file 
* or directory as this abstract pathname. Whether or not two abstract 
* pathnames are equal depends upon the underlying system. On UNIX 
* systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows 
* systems it is not. 
* 
* @param obj The object to be compared with this abstract pathname 
* 
* @return <code>true</code> if and only if the objects are the same; 
*   <code>false</code> otherwise 
*/ 
public boolean equals(Object obj) { 
    if ((obj != null) && (obj instanceof File)) { 
     return compareTo((File)obj) == 0; 
    } 
    return false; 
} 
/** 
* Compares two abstract pathnames lexicographically. The ordering 
* defined by this method depends upon the underlying system. On UNIX 
* systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows 
* systems it is not. 
* 
* @param pathname The abstract pathname to be compared to this abstract 
*     pathname 
* 
* @return Zero if the argument is equal to this abstract pathname, a 
*   value less than zero if this abstract pathname is 
*   lexicographically less than the argument, or a value greater 
*   than zero if this abstract pathname is lexicographically 
*   greater than the argument 
* 
* @since 1.2 
*/ 
public int compareTo(File pathname) { 
    return fs.compare(this, pathname); 
} 
0

Jeśli używasz systemu Windows patrz klasa Win32FileSystem

Metoda porównanie jest jak poniżej, więc jest to bardzo normalne, że twoje obiekty plików są różne.

public int compare(File f1, File f2) { 
     return f1.getPath().compareToIgnoreCase(f2.getPath()); 
    } 

Dodaj te linie w kodzie, a także

 System.out.println(f1.getPath()); 
     System.out.println(f2.getPath()); 

i będzie drukować

.\hello.txt 
hello.txt 

Stąd nie są równe jako porównanie odbywa się za pomocą ścieżki z usługą obiektu pliku

4

Jeśli chcesz tylko porównać zawartość każdego pliku, możesz odczytać zawartość w bajcie ar Promień podobny do tego:

byte[] f1 = Files.readAllBytes(file1); 
byte[] f2 = Files.readAllBytes(file2); 

A następnie porównaj dokładnie to, czego chcesz od tego.

Należy zauważyć, że to wywołanie metody istnieje tylko w języku Java 7. W starszych wersjach Guava i Apache mają metody podobne, ale z różnymi nazwami i szczegółami.

Edit: ALBO lepszym rozwiązaniem (zwłaszcza jeśli porównać dużych plików) może być po prostu porównanie bajt po bajcie zamiast ładowania całego pliku do pamięci, tak:

FileInputStream f1 = new FileInputStream(file1); 
DataInputStream d1 = new DataInputStream(f1); 
FileInputStream f2 = new FileInputStream(file2); 
DataInputStream d2 = new DataInputStream(f2); 

byte b1 = d1.readByte(); 
byte b2 = d2.readByte(); 

a następnie porównać stamtąd.

+0

+1 Przyjemny wpis - nauczyłem się czegoś dzisiaj (nie korzystałem jeszcze z Java 7, cieszę się, że dodałem narzędzie do plików) – user949300

+1

Najpierw porównałbym rozmiar plików, jeśli jest dostępny. – Luciano

+5

jest to bardzo zły pomysł, aby porównać pliki takie jak to – unbeli

7

Aby prawidłowo badania jest równa, należy zadzwonić getCanonicalFile(). na przykład

public static void main(String[] args) throws IOException 
    { 
     File f1 = new File("./hello.txt").getCanonicalFile(); 
     File f2 = new File("hello.txt").getCanonicalFile(); 
     System.out.println("f1: " + f1.getAbsolutePath()); 
     System.out.println("f2: " + f2.getAbsolutePath()); 
     System.out.println("f1.equals(f2) returns " + f1.equals(f2)); 
     System.out.println("f1.compareTo(f2) returns " + f1.compareTo(f2)); 
    } 

Zwróci wartość true dla równych. Zauważ, że getCanonicalFile może rzucić wyjątek IOException, więc dodałem to do podpisu metody.

2

Szybszy sposób na znalezienie dwóch plików znajduje się poniżej.

To tylko propozycja, aby to przerobić.

Nie wiesz, o wydajności (co, jeśli pliki są 10 GB każdego?)

File file = new File("/tmp/file.txt"); 
    File secondFile = new File("/tmp/secondFile.txt"); 

    // Bytes diff 
    byte[] b1 = Files.readAllBytes(file.toPath()); 
    byte[] b2 = Files.readAllBytes(secondFile.toPath()); 

    boolean equals = Arrays.equals(b1, b2); 

    System.out.println("the same? " + equals); 

    // List Diff 
    List<String> c1 = Files.readAllLines(file.toPath()); 
    List<String> c2 = Files.readAllLines(secondFile.toPath()); 

    boolean containsAll = c1.containsAll(c2); 
    System.out.println("the same? " + containsAll);     
} 

EDIT

Ale wciąż Diff na systemie UNIX byłyby znacznie szybsze i gadatliwy. Zależy od tego, co należy porównać.

Powiązane problemy