web-dev-qa-db-ja.com

Javaファイルは等しい

皆さんのことはわかりませんが、少なくとも、以下のコードでは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));
    }
}
21
aandeers

そうではありません。 equalsは絶対パスの同等性を比較しているため(上​​記の場合は次のようになります)。

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

したがって、それらは自然に異なります。

それをサポートするために自分のequalsメソッドを書かなければならないようですよね?

多分そう。しかし、まず第一に、あなたはあなたが何を比較したいのかを知らなければなりませんか?パス名のみ?はいの場合、次のように正規パスを比較します。

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

ただし、2つの異なるファイルのコンテンツを比較する場合は、yes、独自のメソッドを作成する必要があります-または単にインターネット上のどこかからコピーします。

32
G. Demecki

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をスローする可能性があるため、メソッドシグネチャに追加したことに注意してください。

8
user949300

各ファイルの内容のみを比較したい場合は、次のように内容をバイト配列に読み込むことができます。

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

そして、そこからあなたが望むものを正確に比較します。

このメソッド呼び出しはJava 7にのみ存在することに注意してください。古いバージョンの場合、GuavaとApacheには同様の方法がありますが、名前と詳細が異なります。

編集:ORより良いオプション(特に大きなファイルを比較している場合)は、次のように、ファイル全体をメモリにロードするのではなく、単にバイト単位で比較することです。

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

そして、そこから比較します。

5
Brian Snow

2つのファイルを比較するためのより簡単な方法は次のとおりです。

それはそれを回避するための単なる提案です。

パフォーマンスがわからない(ファイルがそれぞれ10 GBの場合はどうなりますか?)

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

[〜#〜]編集[〜#〜]

しかし、それでも、UNIXシステムでのdiffユーティリティははるかに高速で冗長になります。比較する必要があるものによって異なります。

2
DevDio

両方のメソッドの実装は次のとおりです。

/**
 * 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);
}
1
Eng.Fouad

パスの使用に基づいてファイルが同じかどうかを確認したいだけの場合

Java.nio.file.Files#isSameFile

例えば。

Assert.assertTrue(Files.isSameFile(
     new File("some-project\.\hello.txt").toPath(),
     new File("some-project\hello.txt").toPath()
));
0
EliuX

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

したがって、ファイルオブジェクトのパスプロパティを使用して比較が行われるため、これらは等しくありません。

0
fmucar