Java-файл равен - PullRequest
       24

Java-файл равен

20 голосов
/ 19 января 2012

Я не знаю о вас, ребята, но, по крайней мере, я ожидал, что f1 будет равно f2 в приведенном ниже коде, но, очевидно, это не так!Что вы думаете об этом?Кажется, мне нужно написать собственный метод equals для его поддержки, верно?

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

Ответы [ 7 ]

32 голосов
/ 19 января 2012

Нет, это не тот случай. Потому что равно сравнивает равенство абсолютных путей (в вашем случае выше это что-то вроде:

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

Так что они естественно разные.

Кажется, мне нужно написать собственный метод equals для его поддержки, право?

Вероятно, да. Но, прежде всего, вы должны знать, что вы хотите сравнить? Только пути? Если да, сравните его канонический путь следующим образом:

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

Но если вы хотите сравнить содержимое двух разных файлов, то да , вы должны написать свой собственный метод - или просто скопировать из Интернета.

8 голосов
/ 19 января 2012

Чтобы правильно проверить equals, вы должны вызвать getCanonicalFile (). например,

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

Вернет true для равных. Обратите внимание, что getCanonicalFile может выдать IOException, поэтому я добавил это в сигнатуру метода.

4 голосов
/ 19 января 2012

Если вы хотите сравнить только СОДЕРЖАНИЕ каждого файла, вы можете прочитать содержимое в байтовый массив следующим образом:

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

, а затем сравнить то, что вы хотите оттуда.

Обратите внимание, что этот вызов метода существует только в Java 7. В более старых версиях Guava и Apache имеют методы, позволяющие выполнять аналогичные действия, но с разными именами и деталями.

Редактировать: ИЛИ лучший вариант (особенно еслисравнение больших файлов) может заключаться в простом сравнении байтов за байтом, а не в загрузке всего файла в память, например:

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

, а затем сравнение оттуда.

2 голосов
/ 15 ноября 2016

Ниже приведен более быстрый способ сравнения двух файлов.

Это просто предложение обойти это.

Не уверен насчет производительности (что делать, если файлы по 10 ГБ каждый?)

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

РЕДАКТИРОВАТЬ

Но, тем не менее, утилита diff в системе Unix будет намного быстрее и многословнее.Зависит от того, что вам нужно сравнить.

1 голос
/ 19 января 2012

Вот реализация обоих методов:

/**
 * 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 голосов
/ 08 мая 2018

Если вы просто хотите проверить, совпадают ли файлы в зависимости от их пути, используйте

java.nio.file.Files#isSameFile

* 1006 Е.Г. *

Assert.assertTrue(Files.isSameFile(
     new File("some-project\.\hello.txt").toPath(),
     new File("some-project\hello.txt").toPath()
));
0 голосов
/ 19 января 2012

Если вы используете Windows, см. Класс Win32FileSystem

Метод сравнения аналогичен приведенному ниже, поэтому вполне нормально, что ваши файловые объекты отличаются.

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

Добавьте эти строки и в свой код

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

и он напечатает

.\hello.txt
hello.txt

Следовательно, они не равны, так как сравнение выполняется с использованием свойства path объекта File

...