Je ne sais pas pour vous les gars, mais au moins je m'attendais à ce que F1 soit égal à f2 dans le code ci-dessous, mais apparemment ce n'est pas le cas! Que pensez-vous de cela? Il semble que je doive écrire ma propre méthode d'égalité pour la prendre en charge, non?
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));
}
}
Non, ce n'est pas le cas. Parce que equals compare l’égalité des chemins absolus (dans votre cas ci-dessus, cela ressemble à quelque chose comme:
some-project\.\hello.txt
some-project\hello.txt
Donc, ils sont naturellement différents.
Il semble que je doive écrire ma propre méthode d'égalité pour la prendre en charge, N'est-ce pas?
Probablement oui. Mais avant tout, vous devez savoir ce que vous voulez comparer? Seulement les noms de chemin? Si oui, comparez son chemin canonique de la manière suivante:
f1.getCanonicalPath().equals(f2.getCanonicalPath())
Mais si vous voulez comparer le contenu de deux fichiers différents, alors oui , vous devriez écrire votre propre méthode - ou simplement copier depuis quelque part sur Internet.
Pour tester correctement l'égalité, vous devez appeler getCanonicalFile (). par exemple.
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));
}
Reviendra vrai pour égaux. Notez que getCanonicalFile peut générer une exception IOException et que je l'ai ajoutée à la signature de la méthode.
Si vous souhaitez uniquement comparer le contenu de chaque fichier, vous pouvez lire le contenu dans un tableau d'octets comme ceci:
byte[] f1 = Files.readAllBytes(file1);
byte[] f2 = Files.readAllBytes(file2);
Et puis comparez exactement ce que vous voulez à partir de là.
Notez que cet appel de méthode n'existe que dans Java 7. Pour les versions plus anciennes, Guava et Apache disposent de méthodes similaires, mais avec des noms et des détails différents.
Éditer: OR une meilleure option (surtout si vous comparez des fichiers volumineux) peut consister simplement à comparer octet par octet au lieu de charger tout le fichier en mémoire, comme ceci:
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();
Et puis comparer à partir de là.
Le moyen le plus rapide que j'ai trouvé de diff sur deux fichiers est ci-dessous.
C'est juste proposition de contourner le problème.
Pas sûr de la performance (que se passe-t-il si les fichiers font 10 Go chacun?)
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);
}
MODIFIER
Mais malgré tout, l’utilité diff sur un système unix serait beaucoup plus rapide et détaillée.
Voici l'implémentation des deux méthodes:
/**
* 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);
}
Si vous voulez juste vérifier si les fichiers sont les mêmes en fonction de leur chemin, utilisez
Java.nio.file.Files#isSameFile
Par exemple.
Assert.assertTrue(Files.isSameFile(
new File("some-project\.\hello.txt").toPath(),
new File("some-project\hello.txt").toPath()
));
Si vous utilisez Windows, consultez la classe Win32FileSystem
La méthode de comparaison est comme ci-dessous, il est donc très normal que vos objets de fichier soient différents.
public int compare(File f1, File f2) {
return f1.getPath().compareToIgnoreCase(f2.getPath());
}
Ajoutez également ces lignes à votre code
System.out.println(f1.getPath());
System.out.println(f2.getPath());
et ça va imprimer
.\hello.txt
hello.txt
Par conséquent, ils ne sont pas égaux car la comparaison est faite en utilisant le chemin path de l’objet File.