2012-01-19 9 views
19

Non so voi ragazzi, ma almeno mi aspettavo che f1 sarebbe stato uguale a f2 nel codice sottostante ma apparentemente non è il caso! Cosa ne pensi di questo? Sembra che devo scrivere il mio metodo di equità per supportarlo, giusto?Il file Java è uguale a

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

Lo stesso accade con la classe Path di Java 7. Ma esistono metodi come Path.normalize() o Files.isSameFile() – Luciano

+0

Si potrebbe tranquillamente proteggere tutti i visualizzatori di questa domanda mostrando l'output effettivo. Mi aspettavo che 'equals' e' compareTo' avessero risultati contraddittori. Questo non è il caso, 'equals' restituisce false e' compareTo' restituisce -58, che significa lessicograficamente "minore di". @Luciano: Si noti che 'Files.isSameFile' in questo caso proverebbe ad aprire i file poiché i percorsi non sono uguali e potrebbero fallire con' NoSuchFileException'. – bluenote10

risposta

30

No, non è il caso. Perché uguale è confrontare l'uguaglianza di percorsi assoluti (nel caso di cui sopra è qualcosa di simile:.

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

quindi sono naturalmente differenti

Sembra che devo scrivere il mio metodo equals per sostenerla, giusto?

Probabilmente sì. Ma prima di tutto, dovete sapere che cosa si vuole confrontare? nomi di percorso solo? Se sì, confrontare il suo percorso canonico in in questo modo:

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

Ma se si vuole confrontare il contenuto di due file diversi, poi , si dovrebbe scrivere il proprio metodo - o semplicemente copiare da qualche parte su internet.

saluti

+1

In realtà voglio fare qualcosa come "fileList.contiene (file) "e questo metodo chiama il metodo equals. – aandeers

1

Qui è l'attuazione di entrambi i metodi:

/** 
* 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

Se si utilizza Windows vedere Classe Win32FileSystem

Il metodo di confronto è come qui di seguito, quindi è molto normale che i tuoi oggetti file siano diversi.

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

Aggiungere queste righe al codice così

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

e stamperà

.\hello.txt 
hello.txt 

Di conseguenza, essi non sono uguali come il confronto viene fatto con percorso proeprty di oggetto File

4

Se si desidera confrontare solo il CONTENUTO di ciascun file, è possibile leggere il contenuto in un byte ar raggio come questo:

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

E quindi confrontare esattamente quello che vuoi da lì.

Si noti che questa chiamata di metodo esiste solo in Java 7. Per le versioni precedenti, Guava e Apache hanno metodi per fare simili ma con nomi e dettagli diversi.

Edit: O una scelta migliore (soprattutto se si sta confrontando file di grandi dimensioni) potrebbero essere semplicemente confrontare byte per byte, piuttosto che caricare l'intero file in memoria, in questo modo:

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(); 

E poi confrontare da li.

+0

+1 Bel post - Ho imparato qualcosa oggi (non ho ancora usato Java 7, felice di vedere che hanno aggiunto un'utilità File) – user949300

+1

Vorrei confrontare prima la dimensione dei file, se disponibile. – Luciano

+5

è una pessima idea confrontare file come quello – unbeli

7

Per correttamente prova uguale, è necessario chiamare getCanonicalFile(). per esempio.

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)); 
    } 

Restituisce vero per uguale. Nota che getCanonicalFile può lanciare una IOException quindi l'ho aggiunta alla firma del metodo.

2

Il modo più veloce che ho trovato per diff su due file è sotto.

Questa è solo una proposta per risolverlo.

Non sono sicuro circa le prestazioni (cosa succede se i file sono di 10 GB ciascuno?)

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

Ma ancora, l'utilità diff sul sistema Unix sarebbe molto più veloce e dettagliata. Dipende da cosa è necessario confrontare.