HOWTO · Java

Comparar contenido de dos archivos en Java

Este tutorial demuestra cómo comparar el contenido de dos archivos en Java.

En esta página

Java ofrece varias formas de comparar archivos, según necesites comprobar si sus bytes son idénticos, comparar líneas de texto o encontrar la posición del primer byte distinto. Para archivos grandes, usa una comparación en flujo; para comparar líneas de texto decodificado, ten en cuenta que se ignoran los terminadores de línea; usa Files.mismatch() si está disponible en tu entorno de ejecución, Apache Commons IO si el proyecto ya incluye esa dependencia, o Arrays.equals() cuando ambos archivos quepan cómodamente en memoria.

Elige un método para comparar archivos

Método Qué compara Cuándo conviene
Byte por byte Cada byte, incluidos los de la codificación y los terminadores de línea Se necesita comprobar que el contenido sea exactamente igual y los archivos pueden ser grandes
Línea por línea El valor de cada línea decodificada, sin los terminadores Se quiere comparar el texto por líneas, no los bytes almacenados
Files.mismatch() Los bytes y la posición del primer byte distinto El entorno de ejecución ofrece esta API y resulta útil conocer dónde está la diferencia
Apache Commons IO El contenido mediante FileUtils.contentEquals() El proyecto ya incluye Commons IO
Arrays.equals() Dos arreglos de bytes completos Ambos archivos son lo bastante pequeños como para cargarlos en memoria

Una comparación de bytes considera que las codificaciones distintas y las secuencias diferentes de terminadores de línea son contenido distinto. Una comparación por líneas decodifica los caracteres y readLine() elimina los terminadores, por lo que dos archivos con los mismos valores de línea pueden compararse como iguales aunque uno use LF y el otro CRLF. Tampoco distingue entre una última línea terminada en salto de línea y otra sin él. Elige según lo que signifique «igual» para tu aplicación.

Compara archivos byte por byte en Java

Lee los bytes de ambos flujos dentro del mismo bucle. InputStream.read() devuelve un valor entre 0 y 255, o -1 al llegar al final del archivo; comprobar ambos valores permite detectar tanto una diferencia de longitud como un byte distinto. Este enfoque en flujo mantiene un estado pequeño y constante, en vez de cargar ambos archivos en arreglos.

Ejecuta este ejemplo:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;

public class Main {
    static boolean equalByByte(Path first, Path second) throws IOException {
        try (InputStream a = Files.newInputStream(first);
             InputStream b = Files.newInputStream(second)) {
            while (true) {
                int x = a.read();
                int y = b.read();
                if (x != y) return false;
                if (x == -1) return true;
            }
        }
    }

    static boolean equalByLine(Path first, Path second) throws IOException {
        try (java.io.BufferedReader a = Files.newBufferedReader(first, StandardCharsets.UTF_8);
             java.io.BufferedReader b = Files.newBufferedReader(second, StandardCharsets.UTF_8)) {
            while (true) {
                String x = a.readLine();
                String y = b.readLine();
                if (!java.util.Objects.equals(x, y)) return false;
                if (x == null) return true;
            }
        }
    }

    static boolean equalByArrays(Path first, Path second) throws IOException {
        return Arrays.equals(Files.readAllBytes(first), Files.readAllBytes(second));
    }

    public static void main(String[] args) throws IOException {
        Path first = Files.createTempFile("first", ".txt");
        Path second = Files.createTempFile("second", ".txt");
        try {
            Files.write(first, "DelftStack\n".getBytes(StandardCharsets.UTF_8));
            Files.write(second, "DelftStack\n".getBytes(StandardCharsets.UTF_8));
            System.out.println("Byte comparison: " + equalByByte(first, second));
            System.out.println("Line comparison: " + equalByLine(first, second));
            System.out.println("Array comparison: " + equalByArrays(first, second));
        } finally {
            Files.deleteIfExists(first);
            Files.deleteIfExists(second);
        }
    }
}
Byte comparison: true
Line comparison: true
Array comparison: true

La comparación en flujo devuelve false en cuanto encuentra un byte distinto o uno de los flujos llega antes al final, y devuelve true cuando ambos llegan juntos al final del archivo. La construcción try-with-resources cierra los dos flujos incluso si falla la lectura. Files.newInputStream() y las demás operaciones con archivos pueden lanzar IOException, y este ejemplo permite que main propague esa excepción.

Compara archivos línea por línea en Java

Para comparar texto, abre ambos archivos con el mismo juego de caracteres explícito y compara por valor cada par de resultados de readLine(). Objects.equals() admite tanto cadenas como null: si solo un archivo tiene otra línea, los valores son distintos; si ambos devuelven null, los dos han llegado al final. No compares cadenas con ==, que comprueba si dos referencias apuntan al mismo objeto, no si su contenido coincide.

El método de comparación por líneas del ejemplo ejecutable usa UTF-8. Elige el juego de caracteres que corresponda a los archivos que necesitas leer; uno distinto puede cambiar los valores decodificados o provocar errores de decodificación. Como readLine() descarta los terminadores, usa la comparación de bytes si importan los bytes exactos de los saltos de línea.

Compara archivos con Files.mismatch() en Java

Por ejemplo, long position = Files.mismatch(first, second); devuelve -1 si los archivos contienen bytes idénticos. De lo contrario, devuelve la posición, contada desde cero, de su primer byte distinto; si un archivo es prefijo del otro, la posición corresponde al primer byte que sigue al archivo más corto. La documentación de la API de Files.mismatch() describe este comportamiento. Su disponibilidad depende del entorno de ejecución de Java, así que comprueba que el entorno de destino ofrezca este método antes de elegirlo.

Compara archivos con Apache Commons IO en Java

Apache Commons IO ofrece FileUtils.contentEquals(File, File), que devuelve un valor booleano para indicar si el contenido es igual. Añade la dependencia de Commons IO con la versión y el método de gestión de dependencias que ya utilice tu proyecto; esta biblioteca no forma parte de la biblioteca estándar de Java. Por ejemplo, tras importar org.apache.commons.io.FileUtils, puedes llamar a FileUtils.contentEquals(first.toFile(), second.toFile()).

Este método puede lanzar IOException; gestiona o propaga ese error en lugar de tratarlo como un resultado de igualdad. El valor booleano por sí solo no demuestra que se hayan comparado dos archivos existentes: el método puede devolver true si ambas rutas no existen. Si para considerar que son iguales es necesario que se hayan comparado dos archivos, comprueba que ambas entradas existan antes de llamar al método y luego gestiona los errores de E/S según las necesidades de la aplicación.

Compara archivos con Arrays.equals() en Java

Files.readAllBytes() carga cada archivo completo en memoria, y Arrays.equals(byte[], byte[]) compara los bytes resultantes. El método auxiliar del ejemplo muestra este enfoque de la biblioteca estándar. Es conciso y adecuado si se sabe que los archivos son de tamaño moderado, pero los archivos grandes pueden agotar la memoria disponible. Si el tamaño de los archivos es incierto, usa el enfoque en flujo o Files.mismatch() cuando el entorno de ejecución lo admita.

Elige la comparación por líneas cuando necesites comparar texto decodificado y la comparación de bytes cuando necesites comprobar que el contenido almacenado sea exacto. Para archivos grandes, prefiere el enfoque en flujo; usa Files.mismatch() cuando su disponibilidad en el entorno y la posición de la diferencia te resulten útiles; y elige Apache Commons IO si el proyecto ya incluye esa dependencia. Arrays.equals() resulta práctico cuando ambos archivos completos caben con seguridad en memoria.