Determine se dois arquivos armazenam o mesmo conteúdo

Como você escreveria uma function java boolean sameContent(Path file1,Path file2) que determina se os dois caminhos indicados apontam para arquivos que armazenam o mesmo conteúdo? Claro, primeiro, gostaria de verificar se os tamanhos dos arquivos são os mesmos. Esta é uma condição necessária para armazenar o mesmo conteúdo. Mas então eu gostaria de ouvir suas abordagens. Se os dois arquivos estiverem armazenados no mesmo disco rígido (como na maioria dos casos), provavelmente não é a melhor maneira de pular muitas vezes entre os dois streams.

Exatamente o que o método FileUtils.contentEquals do IO do Apache tem em comum e a API está aqui .

Tente algo como:

 File file1 = new File("file1.txt"); File file2 = new File("file2.txt"); boolean isTwoEqual = FileUtils.contentEquals(file1, file2); 

Ele faz as seguintes verificações antes de fazer a comparação:

  • existência de ambos os arquivos
  • Ambos os arquivos que são passados ​​devem ser do tipo de arquivo e não do diretório.
  • comprimento em bytes não deve ser o mesmo.
  • Ambos são arquivos diferentes e não um e o mesmo.
  • Em seguida, compare o conteúdo.

Se você não quiser usar nenhuma biblioteca externa, simplesmente leia os arquivos em matrizes de bytes e compare-os (não funcionará antes do Java-7):

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

usando Arrays.equals .

Se os arquivos forem grandes, em vez de ler os arquivos inteiros em matrizes, você deve usar BufferedInputStream e ler os arquivos chunk-by-chunk conforme explicado aqui .

Se os arquivos forem pequenos, você poderá ler os dois na memory e comparar os arrays de bytes.

Se os arquivos não são pequenos, você pode calcular os hashes do seu conteúdo (por exemplo, MD5 ou SHA-1) um após o outro e comparar os hashes (mas isso ainda deixa uma pequena chance de erro), ou você pode comparar conteúdo, mas para isso você ainda tem que ler os streams alternados.

Aqui está um exemplo:

 boolean sameContent(Path file1, Path file2) throws IOException { final long size = Files.size(file1); if (size != Files.size(file2)) return false; if (size < 4096) return Arrays.equals(Files.readAllBytes(file1), Files.readAllBytes(file2)); try (InputStream is1 = Files.newInputStream(file1); InputStream is2 = Files.newInputStream(file2)) { // Compare byte-by-byte. // Note that this can be sped up drastically by reading large chunks // (eg 16 KBs) but care must be taken as InputStream.read(byte[]) // does not neccessarily read a whole array! int data; while ((data = is1.read()) != -1) if (data != is2.read()) return false; } return true; } 

Isso deve ajudá-lo com seu problema:

 package test; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; public class CompareFileContents { public static void main(String[] args) throws IOException { File file1 = new File("test1.txt"); File file2 = new File("test2.txt"); File file3 = new File("test3.txt"); boolean compare1and2 = FileUtils.contentEquals(file1, file2); boolean compare2and3 = FileUtils.contentEquals(file2, file3); boolean compare1and3 = FileUtils.contentEquals(file1, file3); System.out.println("Are test1.txt and test2.txt the same? " + compare1and2); System.out.println("Are test2.txt and test3.txt the same? " + compare2and3); System.out.println("Are test1.txt and test3.txt the same? " + compare1and3); } } 

Eu tive um cenário onde eu tive que comparar quaisquer dois arquivos (vídeos / imagens / qualquer coisa). Eu fui em frente calculando o md5 para os dois arquivos e comparando-os. Funcionou bem.

 import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5EncoderUtility { public String encodeToMd5(String filePath) { MessageDigest md = null; try { md = MessageDigest.getInstance("SHA1"); } catch (NoSuchAlgorithmException e1) { e1.printStackTrace(); } FileInputStream fis = null; try { fis = new FileInputStream(filePath); } catch (FileNotFoundException e) { e.printStackTrace(); } byte[] dataBytes = new byte[1024]; int nread = 0; try { while ((nread = fis.read(dataBytes)) != -1) { md.update(dataBytes, 0, nread); } } catch (IOException e) { e.printStackTrace(); } byte[] mdbytes = md.digest(); // convert the byte to hex format StringBuffer sb = new StringBuffer(""); for (int i = 0; i < mdbytes.length; i++) { sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1)); } System.out.println("Digest(in hex format):: " + sb.toString()); return sb.toString(); } } 

 public class FileCompareUtility { MD5EncoderUtility md5EncoderUtil = new MD5EncoderUtility(); public boolean compare2Files(String actualFilePath, String expectedFilePath) { if ((md5EncoderUtil.encodeToMd5(actualFilePath)).equals(md5EncoderUtil.encodeToMd5(expectedFilePath))) { System.out.println("The files- "+actualFilePath+" and "+expectedFilePath+" are same"); return true; } else { System.out.println("The files- "+actualFilePath+" and "+expectedFilePath+" are NOT same"); return false; } } } 

E pode ser chamado assim:

  String actualFileComparePath = "D:/Videos/test.mp4"; String expectedFileComparePath = "D:/Videos/test2.mp4"; // This will compare any types of files- here video.Eg-Video fileCompareUtil.compare2Files(actualFileComparePath, expectedFileComparePath);