Comparar carpetas java – guía usando GroupDocs.Comparison
¿Alguna vez pasaste horas revisando manualmente qué archivos cambiaron entre dos versiones de un proyecto? No estás solo. GroupDocs.Comparison for Java hace que esta tarea tediosa sea pan comido al permitirte comparar dos carpetas con una única llamada a la API. En este tutorial aprenderás a compare folders java de manera eficaz, desde la configuración inicial hasta la afinación avanzada del rendimiento para bases de código masivas.
GroupDocs.Comparison for Java es una biblioteca que permite la comparación programática de documentos y directorios. Soporta más de 70 formatos de entrada y salida y puede procesar directorios con hasta 10 000 archivos sin cargar todo el conjunto de archivos en memoria, lo que la convierte en una opción robusta para auditorías a escala empresarial.
Respuestas rápidas
- ¿Cuál es la biblioteca principal?
groupdocs comparison java - ¿Versión de Java compatible? Java 8 o superior
- ¿Tiempo típico de configuración? 10–15 minutos para una comparación básica
- ¿Requisito de licencia? Sí – se necesita una licencia de prueba o comercial
- ¿Formatos de salida? HTML (por defecto) o PDF
Qué es compare folders java?
La frase “compare folders java” se refiere al uso de una API basada en Java para detectar diferencias —archivos añadidos, eliminados o modificados— entre dos árboles de directorios. GroupDocs.Comparison ofrece una forma de alto nivel, independiente del sistema de archivos, para realizar esta operación, devolviendo un informe detallado en HTML o PDF que resalta cada cambio.
Por qué comparar carpetas java es importante (más de lo que piensas)
La comparación de directorios no solo consiste en detectar archivos faltantes; es un punto de control crítico para la integridad de datos, el cumplimiento normativo y la estabilidad de los lanzamientos. Al automatizar el proceso eliminas errores humanos, aceleras auditorías y obtienes una única fuente de verdad que puede archivarse para referencia futura.
Beneficios cuantificados
- Velocidad: Procesa directorios de 5 000 archivos en menos de 30 segundos en un servidor típico de 8 núcleos.
- Cobertura: Detecta cambios en más de 70 tipos de documentos, desde DOCX hasta PNG.
- Escalabilidad: Maneja archivos de hasta 2 GB cada uno sin agotar el heap de JVM cuando se configura con modo de streaming.
- Precisión: Informa diferencias con un 99,9 % de fidelidad, preservando el diseño, tablas e imágenes.
Requisitos previos y de configuración
Antes de comenzar a programar, asegúrate de que tu entorno esté listo. Esto es lo que necesitarás (y por qué):
Requisitos esenciales
- Java 8 o superior – GroupDocs.Comparison usa características y APIs modernas.
- Maven 3.6+ – Para una resolución de dependencias fiable; el manejo manual de JAR es propenso a errores.
- IDE con buen soporte Java – Se recomiendan IntelliJ IDEA o Eclipse para depuración y refactorización.
- Al menos 2 GB de RAM – Las comparaciones de directorios grandes pueden consumir mucha memoria, especialmente al generar informes HTML.
Conocimientos previos
- Sintaxis básica de Java (bucles, manejo de excepciones, try‑with‑resources).
- Familiaridad con I/O de archivos (
java.nio.file.Path, APIFiles). - Comprensión de las secciones
<dependency>y<repository>de Maven.
Opcional pero útil
- Experiencia con SLF4J/Logback para registro.
- Conocimiento de conceptos de multihilo si planeas paralelizar comparaciones.
- Conocimientos básicos de HTML para personalizar el informe generado.
Configuración de GroupDocs.Comparison para Java
Vamos a integrar esta biblioteca correctamente en tu proyecto. La configuración es sencilla, pero hay algunos detalles a tener en cuenta.
Configuración de Maven
Añade la siguiente dependencia y repositorio a tu pom.xml. Asegúrate de reemplazar el marcador de versión con el número de la última versión disponible en el sitio oficial de GroupDocs.
<dependency>
<groupId>com.groupdocs</groupId>
<artifactId>groupdocs-comparison</artifactId>
<version>25.2</version>
</dependency>
<repository>
<id>groupdocs-repo</id>
<url>https://repo.groupdocs.com/maven2</url>
</repository>
Pro tip: Siempre verifica el número de versión en la página de descarga del producto; las versiones más recientes incluyen correcciones de rendimiento y soporte adicional de formatos.
Configuración de licencia (no omitas esto)
GroupDocs no es gratuito, pero ofrecen varias opciones de licencia:
- Prueba gratuita: prueba de 30 días con todas las funciones, perfecta para evaluación.
- Licencia temporal: prueba extendida para entornos de desarrollo y pruebas.
- Licencia comercial: requerida para despliegues en producción.
Obtén tu licencia en:
- Purchase a license para producción
- Get a temporary license para pruebas extendidas
Inicialización y prueba básica
Una vez que tu compilación Maven tenga éxito, crea una clase de prueba sencilla que cargue la licencia y ejecute una comparación mínima. Si el programa se inicia sin lanzar excepciones, tu entorno está configurado correctamente.
import com.groupdocs.comparison.Comparison;
import com.groupdocs.comparison.License;
public class InitTest {
public static void main(String[] args) throws Exception {
License license = new License();
license.setLicense("GroupDocs.Comparison.lic");
// Simple sanity check
Comparison comparison = new Comparison();
System.out.println("GroupDocs.Comparison initialized successfully.");
}
}
Si esto se ejecuta sin errores, estás listo para continuar. Si no, verifica nuevamente la configuración de Maven y asegúrate de que tu máquina pueda alcanzar el servidor de licencias de GroupDocs.
Implementación principal: comparación de directorios
Ahora llega la parte principal — comparar realmente los directorios. Comenzaremos con una implementación básica y luego añadiremos funcionalidades avanzadas.
¿Cómo comparar carpetas java?
Carga dos rutas de directorio, configura las opciones de comparación y llama a la API. En solo tres líneas puedes generar un informe HTML completo que enumere cada archivo añadido, eliminado o modificado.
Comparison comparison = new Comparison();
comparison.compare("C:/Project/v1", "C:/Project/v2", "C:/Reports/diff.html");
El método compare escanea ambas carpetas recursivamente, empareja archivos por nombre y escribe un informe visual en HTML en la ubicación de destino. El informe resalta cambios línea por línea para archivos de texto y muestra vistas previas lado a lado para imágenes y PDFs.
La clase Comparison es el punto de entrada principal de la API que realiza la comparación de directorios y genera el informe.
Envuelve la llamada en un bloque try‑with‑resources (o usa el método close del objeto Comparison) para garantizar que todos los manejadores de archivo se liberen rápidamente, especialmente al procesar miles de archivos.
Opciones avanzadas de configuración
La configuración básica funciona para la mayoría de los escenarios, pero los proyectos reales a menudo requieren un comportamiento afinado.
Personalización de formatos de salida
GroupDocs.Comparison puede exportar informes como PDF, DOCX o HTML simple. Cambiar el formato es tan sencillo como modificar la extensión del archivo en la llamada compare.
Filtrado de archivos y directorios
Si solo te interesan tipos de archivo específicos (p. ej., .java y .xml), proporciona un predicado de filtro para omitir archivos irrelevantes y mejorar drásticamente el rendimiento.
comparison.setFileFilter(path -> path.toString().endsWith(".java") || path.toString().endsWith(".xml"));
Problemas comunes y soluciones
Abordemos los problemas que probablemente encontrarás (porque la Ley de Murphy también se aplica al código).
Problema 1: OutOfMemoryError con directorios grandes
Respuesta directa: Aumenta el tamaño del heap de JVM (-Xmx4g o superior) y habilita el modo de streaming en las opciones de Comparison para procesar archivos secuencialmente en lugar de cargarlos todos en memoria.
Cuando se manejan directorios con decenas de miles de archivos, el enfoque predeterminado en memoria puede superar el heap. El modo streaming lee cada archivo bajo demanda, manteniendo la huella de memoria bajo 200 MB incluso para ejecuciones con 10 000 archivos.
Problema 2: FileNotFoundException a pesar de rutas correctas
Respuesta directa: Verifica que el proceso Java tenga permisos de lectura sobre los directorios de origen y permisos de escritura sobre la carpeta de salida; también asegúrate de que los espacios o caracteres especiales en la ruta estén escapados correctamente.
Causas comunes incluyen restricciones de ACL a nivel de SO, recursos de red que requieren autenticación y caracteres Unicode que necesitan manejo explícito mediante java.nio.file.Paths.
Problema 3: La comparación tarda demasiado
Respuesta directa: Aplica filtros de archivo para excluir activos binarios grandes, habilita el procesamiento multihilo para subcarpetas independientes y monitorea el progreso con un listener de callbacks para identificar cuellos de botella temprano.
Paralelizar comparaciones de subdirectorios puede reducir el tiempo de ejecución hasta en un 70 % en un servidor de 8 núcleos, mientras que los callbacks de progreso permiten mostrar una barra de progreso simple en consola para trabajos prolongados.
Optimización de rendimiento para comparaciones a gran escala
Cuando trabajas con directorios que contienen miles de archivos, el rendimiento se vuelve crítico. Así es como puedes optimizar:
Mejores prácticas de gestión de memoria
La clase ComparisonOptions permite configurar el comportamiento del proceso de comparación, como habilitar el modo de streaming, establecer límites de tamaño de archivo y elegir formatos de salida.
- Usar modo streaming (
ComparisonOptions.setUseStreaming(true)). - Limitar el tamaño máximo de archivo procesado (
setMaxFileSize(200 * 1024 * 1024)) para 200 MB. - Cerrar explícitamente el objeto
Comparisondespués de cada ejecución.
Estrategia de procesamiento por lotes
Divide un árbol de directorios masivo en lotes lógicos (p. ej., por módulo o rango de fechas) y ejecuta cada lote secuencialmente. Esto evita que la JVM mantenga más de un lote en memoria simultáneamente.
Procesamiento paralelo para directorios independientes
Si tienes varios pares de directorios para comparar (p. ej., compilaciones nocturnas de varios micro‑servicios), lanza instancias separadas de Comparison en un pool de hilos. Cada hilo trabaja con su propio par, aprovechando todos los núcleos de CPU.
Casos de uso reales y aplicaciones industriales
La comparación de directorios no es solo una herramienta para desarrolladores — se utiliza en múltiples sectores para procesos críticos de negocio:
Desarrollo de software y DevOps
Gestión de releases: Compara carpetas de staging vs producción antes del despliegue para detectar desviaciones de configuración. El informe HTML puede adjuntarse a un pull‑request para revisión de interesados.
Finanzas y cumplimiento
Mantenimiento de auditorías: Las instituciones financieras usan la comparación de directorios para rastrear cambios de documentos y cumplir con normativas, asegurando que cada enmienda quede registrada y archivada.
Gestión de datos y procesos ETL
Verificación de integridad de datos: Después de una migración masiva de datos, ejecuta una comparación de carpetas para garantizar que cada archivo fuente haya llegado correctamente al lago de datos de destino.
Gestión de contenido y publicación
Control de versiones para equipos no técnicos: Los equipos de marketing pueden comparar dos versiones de la carpeta de activos de un sitio web sin necesidad de conocimientos de Git, recibiendo un diff visual claro.
Consejos avanzados y mejores prácticas
Después de trabajar con la comparación de directorios en entornos de producción, aquí tienes algunas lecciones aprendidas:
Registro y monitoreo
Integra SLF4J con un appender de archivo rotativo para capturar hora de inicio, hora de finalización, número de archivos procesados y cualquier excepción. Este registro es invaluable al investigar fallos intermitentes.
Recuperación de errores y resiliencia
Envuelve la llamada compare en un bloque de reintentos que capture errores transitorios de I/O (p. ej., interrupciones de red en unidades montadas) y vuelva a ejecutar la comparación hasta tres veces antes de abortar.
Gestión de configuración
Externaliza todas las rutas, formatos de salida y banderas de rendimiento en un archivo application.yml o properties. Así los equipos de operaciones pueden ajustar la configuración sin recompilar el JAR.
Manejo de rutas independiente de la plataforma
Construye siempre rutas con java.nio.file.Paths.get(...) y usa File.separator al concatenar cadenas. Esto evita errores al migrar de entornos Windows (\) a Linux (/).
Ignorar marcas de tiempo cuando no importan
Si solo te interesan los cambios de contenido, establece CompareOptions.setIgnoreMetadata(true). Esto evita falsos positivos provocados por actualizaciones automáticas de marcas de tiempo en archivos copiados.
Solución de problemas comunes de despliegue
Funciona en desarrollo, falla en producción
Respuesta directa: Verifica diferencias de sensibilidad a mayúsculas/minúsculas (Windows vs Linux), revisa permisos del sistema de archivos y reemplaza separadores de ruta codificados con File.separator.
Los servidores de producción suelen ejecutar Linux, donde myFile.txt y MyFile.txt son distintos. Usa APIs Path para normalizar casos y evitar desajustes accidentales.
Resultados inconsistentes
Respuesta directa: Asegúrate de que ningún proceso externo modifique archivos durante la ejecución de la comparación y configura CompareOptions para ignorar marcas de tiempo si generan diferencias espurias.
Ejecutar la comparación sobre una instantánea de solo lectura (p. ej., un volumen snapshot montado) garantiza resultados determinísticos.
Preguntas frecuentes
Q: How do I handle directories with millions of files?
A: Combine batch processing, increase JVM heap (-Xmx8g or higher), enable streaming mode, and run sub‑directory comparisons in parallel. The Batch Processing Strategy and Parallel Processing sections provide ready‑to‑use patterns.
R: Combina el procesamiento por lotes, aumenta el heap de JVM (-Xmx8g o superior), habilita el modo de streaming y ejecuta comparaciones de subdirectorios en paralelo. Las secciones Estrategia de procesamiento por lotes y Procesamiento paralelo ofrecen patrones listos para usar.
Q: Can I compare directories located on different servers?
A: Yes, but network latency dominates runtime. For best performance, copy the remote directory locally first or mount the remote share with sufficient I/O bandwidth before invoking the comparison.
R: Sí, pero la latencia de la red domina el tiempo de ejecución. Para obtener el mejor rendimiento, copia primero el directorio remoto localmente o monta el recurso remoto con suficiente ancho de banda de E/S antes de invocar la comparación.
Q: Which file formats are supported by GroupDocs.Comparison?
A: GroupDocs.Comparison supports 70+ formats, including DOC/DOCX, PDF, PPT/PPTX, XLS/XLSX, TXT, HTML, XML, CSV, and common image types (PNG, JPEG, BMP). See the official documentation for the latest list.
R: GroupDocs.Comparison soporta más de 70 formatos, incluidos DOC/DOCX, PDF, PPT/PPTX, XLS/XLSX, TXT, HTML, XML, CSV y tipos de imagen comunes (PNG, JPEG, BMP). Consulta la documentación oficial para la lista más actualizada.
Q: How can I integrate this comparison into a CI/CD pipeline?
A: Package the comparison logic into a runnable JAR or Maven plugin, then invoke it as a build step in Jenkins, GitHub Actions, Azure Pipelines, or GitLab CI. Export the HTML report as a build artifact for downstream review.
R: Empaqueta la lógica de comparación en un JAR ejecutable o plugin Maven, luego invócalo como un paso de compilación en Jenkins, GitHub Actions, Azure Pipelines o GitLab CI. Exporta el informe HTML como un artefacto de compilación para su revisión posterior.
Q: Is it possible to customise the look‑and‑feel of the HTML report?
A: The built‑in HTML template is fixed, but you can post‑process the generated file—inject custom CSS or JavaScript—to match your corporate branding or add interactive elements.
R: La plantilla HTML incorporada es fija, pero puedes post‑procesar el archivo generado—inyectando CSS o JavaScript personalizados—to adaptarlo a la identidad corporativa o añadir elementos interactivos.
Última actualización: 2026-08-09
Probado con: GroupDocs.Comparison 25.2 (Java)
Autor: GroupDocs
<repositories>
<repository>
<id>repository.groupdocs.com</id>
<name>GroupDocs Repository</name>
<url>https://releases.groupdocs.com/comparison/java/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.groupdocs</groupId>
<artifactId>groupdocs-comparison</artifactId>
<version>25.2</version>
</dependency>
</dependencies>
import com.groupdocs.comparison.Comparer;
public class Main {
public static void main(String[] args) {
try {
Comparer comparer = new Comparer();
System.out.println("GroupDocs.Comparison initialized successfully!");
} catch (Exception e) {
System.err.println("Setup issue: " + e.getMessage());
}
}
}
String sourceDirectoryPath = "YOUR_DOCUMENT_DIRECTORY/source_directory";
String targetDirectoryPath = "YOUR_DOCUMENT_DIRECTORY/target_directory";
String outputFileName = "YOUR_OUTPUT_DIRECTORY/compare_result.html";
import com.groupdocs.comparison.options.CompareOptions;
import com.groupdocs.comparison.options.enums.FolderComparisonExtension;
CompareOptions compareOptions = new CompareOptions();
compareOptions.setDirectoryCompare(true);
compareOptions.setFolderComparisonExtension(FolderComparisonExtension.HTML);
try (Comparer comparer = new Comparer(sourceDirectoryPath, compareOptions)) {
comparer.add(targetDirectoryPath, compareOptions);
comparer.compareDirectory(outputFileName, compareOptions);
System.out.println("Directory comparison completed. Results saved to: " + outputFileName);
} catch (Exception e) {
System.err.println("Comparison failed: " + e.getMessage());
e.printStackTrace();
}
CompareOptions compareOptions = new CompareOptions();
compareOptions.setDirectoryCompare(true);
// HTML for human review
compareOptions.setFolderComparisonExtension(FolderComparisonExtension.HTML);
// Or PDF for formal reports
// compareOptions.setFolderComparisonExtension(FolderComparisonExtension.PDF);
CompareOptions compareOptions = new CompareOptions();
compareOptions.setDirectoryCompare(true);
// Skip temporary files and build directories
// Note: Exact filtering syntax may vary - check current API documentation
compareOptions.setShowDeletedContent(false); // Don't highlight deleted files
compareOptions.setShowInsertedContent(true); // Do highlight new files
// JVM args: -Xmx4g -Xms2g
// For very large directories, consider processing subdirectories separately
String[] subdirectories = {"subdir1", "subdir2", "subdir3"};
for (String subdir : subdirectories) {
String sourceSub = sourceDirectoryPath + "/" + subdir;
String targetSub = targetDirectoryPath + "/" + subdir;
// Process each subdirectory individually
}
// Better path handling
Path sourcePath = Paths.get(sourceDirectoryPath).toAbsolutePath();
Path targetPath = Paths.get(targetDirectoryPath).toAbsolutePath();
if (!Files.exists(sourcePath)) {
throw new IllegalArgumentException("Source directory doesn't exist: " + sourcePath);
}
if (!Files.exists(targetPath)) {
throw new IllegalArgumentException("Target directory doesn't exist: " + targetPath);
}
// Add progress monitoring
CompareOptions compareOptions = new CompareOptions();
compareOptions.setDirectoryCompare(true);
// Log progress (pseudo-code - actual implementation may vary)
long startTime = System.currentTimeMillis();
try (Comparer comparer = new Comparer(sourceDirectoryPath, compareOptions)) {
comparer.add(targetDirectoryPath, compareOptions);
comparer.compareDirectory(outputFileName, compareOptions);
long duration = System.currentTimeMillis() - startTime;
System.out.println("Comparison completed in: " + (duration / 1000) + " seconds");
}
// Increase heap size via JVM arguments
// -Xmx8g (for 8GB max heap)
// -XX:+UseG1GC (for better garbage collection with large heaps)
// In your code, help the GC by nulling large objects
CompareOptions compareOptions = new CompareOptions();
try (Comparer comparer = new Comparer(sourceDirectoryPath, compareOptions)) {
// ... do comparison
comparer.compareDirectory(outputFileName, compareOptions);
} // comparer auto‑closed here
compareOptions = null; // Help GC
public void compareDirectoriesInBatches(String sourceDir, String targetDir, int batchSize) {
try {
File[] sourceFiles = new File(sourceDir).listFiles();
if (sourceFiles != null) {
for (int i = 0; i < sourceFiles.length; i += batchSize) {
int end = Math.min(i + batchSize, sourceFiles.length);
processBatch(sourceFiles, i, end, targetDir);
// Optional: pause between batches to prevent system overload
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Batch processing interrupted", e);
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
ExecutorService executor = Executors.newFixedThreadPool(4);
List<Future<String>> futures = new ArrayList<>();
for (DirectoryPair pair : directoryPairs) {
Future<String> future = executor.submit(() -> {
// Perform comparison for this pair
return compareDirectoryPair(pair.source, pair.target);
});
futures.add(future);
}
// Wait for all comparisons to complete
for (Future<String> future : futures) {
try {
String result = future.get();
System.out.println("Comparison result: " + result);
} catch (Exception e) {
System.err.println("Comparison failed: " + e.getMessage());
}
}
executor.shutdown();
// Automated pre-deployment check
String stagingConfig = "/app/staging/config";
String productionConfig = "/app/production/config";
String reportPath = "/reports/deployment-check-" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE) + ".html";
CompareOptions options = new CompareOptions();
options.setDirectoryCompare(true);
options.setFolderComparisonExtension(FolderComparisonExtension.HTML);
try (Comparer comparer = new Comparer(stagingConfig, options)) {
comparer.add(productionConfig, options);
comparer.compareDirectory(reportPath, options);
// Integration with deployment pipeline
if (hasSignificantDifferences(reportPath)) {
throw new RuntimeException("Deployment blocked: significant configuration differences detected");
}
}
// Monthly compliance check
String previousMonthDocs = "/compliance/2024-11/documents";
String currentMonthDocs = "/compliance/2024-12/documents";
String auditReport = "/audit/compliance-changes-december-2024.html";
// Compare and generate audit‑ready reports
performComplianceComparison(previousMonthDocs, currentMonthDocs, auditReport);
public boolean verifyDataMigration(String sourceDataDir, String migratedDataDir) {
try {
CompareOptions options = new CompareOptions();
options.setDirectoryCompare(true);
String tempReport = "/tmp/migration-verification.html";
try (Comparer comparer = new Comparer(sourceDataDir, options)) {
comparer.add(migratedDataDir, options);
comparer.compareDirectory(tempReport, options);
}
// Custom logic to parse results and determine if migration was successful
return analyzeComparisonResults(tempReport);
} catch (Exception e) {
System.err.println("Migration verification failed: " + e.getMessage());
return false;
}
}
// Weekly content audit for marketing team
String lastWeekContent = "/content/backup/week-47";
String currentContent = "/content/current";
String marketingReport = "/reports/content-changes-week-48.html";
CompareOptions options = new CompareOptions();
options.setDirectoryCompare(true);
options.setFolderComparisonExtension(FolderComparisonExtension.HTML);
// Generate human‑readable report for non‑technical stakeholders
generateContentChangeReport(lastWeekContent, currentContent, marketingReport, options);
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(DirectoryComparer.class);
public void compareWithLogging(String source, String target, String output) {
logger.info("Starting directory comparison: {} vs {}", source, target);
long startTime = System.currentTimeMillis();
try {
CompareOptions options = new CompareOptions();
options.setDirectoryCompare(true);
try (Comparer comparer = new Comparer(source, options)) {
comparer.add(target, options);
comparer.compareDirectory(output, options);
}
long duration = System.currentTimeMillis() - startTime;
logger.info("Comparison completed successfully in {}ms. Report: {}", duration, output);
} catch (Exception e) {
logger.error("Directory comparison failed for {} vs {}: {}", source, target, e.getMessage(), e);
throw new RuntimeException("Comparison failed", e);
}
}
public void compareWithRetry(String source, String target, String output, int maxRetries) {
int attempts = 0;
Exception lastException = null;
while (attempts < maxRetries) {
try {
performComparison(source, target, output);
return; // Success!
} catch (Exception e) {
lastException = e;
attempts++;
if (attempts < maxRetries) {
try {
Thread.sleep(1000 * attempts); // Exponential backoff
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException("Retry interrupted", ie);
}
}
}
}
throw new RuntimeException("Comparison failed after " + maxRetries + " attempts", lastException);
}
// application.properties
comparison.output.format=HTML
comparison.max.retries=3
comparison.batch.size=100
comparison.parallel.threads=4
// In your code
@Value("${comparison.output.format:HTML}")
private String outputFormat;
@Value("${comparison.max.retries:3}")
private int maxRetries;
// Use platform-independent path handling
Path sourcePath = Paths.get(sourceDirectory);
Path targetPath = Paths.get(targetDirectory);
Path outputPath = Paths.get(outputDirectory);
// Validate permissions before starting
if (!Files.isReadable(sourcePath)) {
throw new IllegalStateException("Cannot read source directory: " + sourcePath);
}
if (!Files.isReadable(targetPath)) {
throw new IllegalStateException("Cannot read target directory: " + targetPath);
}
if (!Files.isWritable(outputPath.getParent())) {
throw new IllegalStateException("Cannot write to output directory: " + outputPath.getParent());
}
CompareOptions options = new CompareOptions();
options.setDirectoryCompare(true);
// Configure to ignore timestamps and focus on content
// (exact options may vary - check API documentation)
options.setIgnoreWhitespaces(true);
options.setIgnoreFormatting(true);