2012-01-19 15 views
19

No sé ustedes, pero al menos yo esperaba que f1 fuera igual a f2 en el siguiente código, ¡pero aparentemente ese no es el caso! ¿Qué piensas sobre esto? Parece que tengo que escribir mi propio método igual para apoyarlo, ¿no?El archivo de Java es igual 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 mismo ocurre con la clase de ruta de Java 7. Pero existen métodos como Path.normalize() o Files.isSameFile() – Luciano

+0

Puede proteger a todos los lectores de esta pregunta en algún momento mostrando el resultado real. Esperaba que 'igual' y' compareTo' tuvieran resultados contradictorios. Este no es el caso, 'equals' devuelve false y' compareTo' devuelve -58, lo que significa lexicográficamente "less than". @Luciano: Tenga en cuenta que 'Files.isSameFile' en este caso trataría de abrir los archivos ya que las rutas no son iguales y podrían fallar con' NoSuchFileException'. – bluenote10

Respuesta

30

No, no es el caso. Debido es igual a es comparar la igualdad de rutas absolutas (en su caso por encima de ella es algo así como:.

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

por lo que son naturalmente diferentes

Parece como si tuviera que escribir mi propio método equals para apoyarlo, ¿verdad?

Probablemente sí. Pero en primer lugar, usted tiene que saber lo que se quiere comparar? Sólo los nombres de ruta? Si es así, comparar su ruta canónica en de esta manera:

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

Pero si desea comparar el contenido de dos archivos diferentes, entonces sí , debe escribir su propio método - o simplemente copiar desde algún lugar de Internet.

Saludos

+1

Realmente quiero hacer algo como "fileList".contiene (archivo) "y este método llama al método igual. – aandeers

1

Aquí es la aplicación de ambos métodos:

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

Si está utilizando ventanas ver la clase Win32FileSystem

El método de comparación es como el de abajo, por lo que es muy Es normal que los objetos de su archivo sean diferentes.

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

Añadir las líneas de su código, así

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

y se imprimirá

.\hello.txt 
hello.txt 

Por lo tanto no son iguales que la comparación se realiza utilizando proeprty camino del objeto File

4

Si solo quiere comparar los CONTENIDOS de cada archivo, puede leer los contenidos en un byte ar rayo como este:

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

Y luego compare exactamente lo que quiere desde allí.

Tenga en cuenta que esta llamada a método solo existe en Java 7. Para versiones anteriores, Guava y Apache tienen métodos para hacer lo mismo pero con diferentes nombres y detalles.

Editar: O una mejor opción (especialmente si usted está comparando archivos de gran tamaño) pueden ser simplemente comparar byte a byte en lugar de cargar todo el archivo en la memoria, así:

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

Y luego comparar desde allí.

+0

+1 Publicación interesante: hoy aprendí algo (todavía no he usado Java 7, me alegro de que hayan agregado una utilidad de archivos) – user949300

+1

Primero compararía el tamaño de los archivos, si está disponible. – Luciano

+5

es una idea increíblemente mala comparar archivos como ese – unbeli

7

Para adecuadamente es igual a la prueba, debe llamar getCanonicalFile(). p.ej.

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

Volverá true para iguales. Tenga en cuenta que getCanonicalFile puede arrojar una IOException, así que lo agregué a la firma del método.

2

La forma más rápida que encontré para diferenciar en dos archivos es la siguiente.

Eso es solo una propuesta para solucionarlo.

No estoy seguro sobre el rendimiento (lo que si los archivos son de 10 GB cada uno?)

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

EDITAR

Pero aún así, diff en el sistema Unix sería mucho más rápido y detallado. Depende de lo que necesite comparar.