Mappák összehasonlítása Java – útmutató a GroupDocs.Comparison használatával
Eltöltöttél már órákat kézzel ellenőrizve, mely fájlok változtak két projektverzió között? Nem vagy egyedül. GroupDocs.Comparison for Java megkönnyíti ezt a fárasztó feladatot, lehetővé téve, hogy egyetlen API hívással két mappát hasonlíts össze. Ebben az útmutatóban megtanulod, hogyan compare folders java hatékonyan, az első beállítástól a nagy kódbázisokhoz való fejlett teljesítményoptimalizálásig.
GroupDocs.Comparison for Java egy könyvtár, amely lehetővé teszi a dokumentumok és könyvtárak programozott összehasonlítását. Több mint 70 bemeneti és kimeneti formátumot támogat, és akár 10 000 fájlt tartalmazó könyvtárakat is feldolgozhat anélkül, hogy az egész fájlkészletet memóriába töltené, így robusztus választás vállalati szintű auditokhoz.
Gyors válaszok
- Mi a fő könyvtár?
groupdocs comparison java - Támogatott Java verzió? Java 8 vagy újabb
- Tipikus beállítási idő? 10–15 perc egy alap összehasonlításhoz
- Licenc követelmény? Igen – próbaverzió vagy kereskedelmi licenc szükséges
- Kimeneti formátumok? HTML (alapértelmezett) vagy PDF
Mi a compare folders java?
A „compare folders java” kifejezés egy Java‑alapú API használatára utal, amely a két könyvtárfa közötti különbségeket – hozzáadott, eltávolított vagy módosított fájlokat – észleli. A GroupDocs.Comparison magas szintű, fájlrendszer‑független módot biztosít ennek a műveletnek a végrehajtásához, részletes HTML vagy PDF jelentést adva, amely kiemeli minden változást.
Miért fontos a compare folders java (több, mint gondolnád)
A könyvtárak összehasonlítása nem csak a hiányzó fájlok felderítéséről szól; kritikus ellenőrzési pont az adat integritás, a szabályozási megfelelés és a kiadás stabilitása szempontjából. A folyamat automatizálásával kiküszöbölöd az emberi hibákat, felgyorsítod az auditokat, és egyetlen igazságforrást kapsz, amely archiválható későbbi hivatkozásként.
Mennyiségi előnyök
- Sebesség: 5 000 fájlt tartalmazó könyvtárakat dolgoz fel 30 másodperc alatt egy tipikus 8‑magos szerveren.
- Fedezet: Több mint 70 dokumentumtípus változását észleli, a DOCX‑től a PNG‑ig.
- Skálázhatóság: 2 GB‑nál nagyobb fájlokat is kezel, anélkül hogy a JVM heap-et kimerítené, ha streaming módra van beállítva.
- Pontosság: 99,9 % pontossággal jelenti a különbségeket, megőrizve a elrendezést, táblázatokat és képeket.
Előfeltételek és beállítási követelmények
Mielőtt elkezdenénk kódolni, győződj meg róla, hogy a környezet készen áll. Íme, amire szükséged lesz (és miért):
Alapvető követelmények
- Java 8 vagy újabb – A GroupDocs.Comparison modern nyelvi funkciókat és API‑kat használ.
- Maven 3.6+ – Megbízható függőségfeloldáshoz; a kézi JAR kezelése hibára hajlamos.
- IDE, amely jó Java támogatással rendelkezik – Az IntelliJ IDEA vagy az Eclipse ajánlott a hibakereséshez és refaktoráláshoz.
- Legalább 2 GB RAM – Nagy könyvtárak összehasonlítása jelentős memóriát fogyaszthat, különösen HTML jelentések generálásakor.
Tudás előfeltételek
- Alap Java szintaxis (ciklusok, kivételkezelés, try‑with‑resources).
- Ismeret a fájl I/O‑val (
java.nio.file.Path,FilesAPI). - Maven
<dependency>és<repository>szekcióinak megértése.
Opcionális, de hasznos
- Tapasztalat az SLF4J/Logback naplózással.
- Többszálas koncepciók ismerete, ha párhuzamos összehasonlítást tervezel.
- Alap HTML ismeretek a generált jelentés testreszabásához.
A GroupDocs.Comparison beállítása Java-hoz
Integráljuk megfelelően ezt a könyvtárat a projektedbe. A beállítás egyszerű, de néhány trükkre érdemes odafigyelni.
Maven konfiguráció
Tedd a következő függőséget és tárolót a pom.xml fájlodba. Ügyelj arra, hogy a verzióhelyőrzőt a hivatalos GroupDocs oldalról a legújabb kiadási számmal cseréld le.
<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 tipp: Mindig ellenőrizd a verziószámot a termék letöltési oldalán; az újabb kiadások teljesítményjavításokat és további formátumtámogatást tartalmaznak.
Licenc beállítása (ne hagyd ki)
A GroupDocs nem ingyenes, de több licencelési lehetőséget kínál:
- Ingyenes próba: 30‑napos próba teljes funkciókészlettel – tökéletes értékeléshez.
- Ideiglenes licenc: Kiterjesztett próba fejlesztési és tesztelési környezetekhez.
- Kereskedelmi licenc: Szükséges a termelési környezethez.
Szerezd be a licencet:
- Licenc vásárlása a termeléshez
- Ideiglenes licenc beszerzése kiterjesztett teszteléshez
Alap inicializálás és tesztelés
Miután a Maven build sikeres, hozz létre egy egyszerű tesztosztályt, amely betölti a licencet és egy minimális összehasonlítást futtat. Ha a program kivétel nélkül elindul, a környezet helyesen van konfigurálva.
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.");
}
}
Ha ez hibák nélkül fut, készen állsz a folytatásra. Ha nem, ellenőrizd újra a Maven beállításaidat, és győződj meg róla, hogy a géped el tudja érni a GroupDocs licencszervert.
Alap megvalósítás: könyvtárak összehasonlítása
Most jön a fő rész — valódi könyvtárak összehasonlítása. Kezdünk egy alap megvalósítással, majd hozzáadunk fejlett funkciókat.
Hogyan hasonlítsuk össze a mappákat java?
Tölts be két könyvtárútvonalat, konfiguráld a összehasonlítási beállításokat, és hívd meg az API‑t. Mindössze három sorban teljes HTML diff jelentést generálhatsz, amely felsorolja minden hozzáadott, törölt vagy módosított fájlt.
Comparison comparison = new Comparison();
comparison.compare("C:/Project/v1", "C:/Project/v2", "C:/Reports/diff.html");
A compare metódus rekurzívan beolvassa mindkét mappát, név alapján párosítja a fájlokat, és egy vizuális HTML jelentést ír a célhelyre. A jelentés soronként kiemeli a szöveges fájlok változásait, és oldalról‑oldalra előnézetet mutat a képek és PDF‑ek esetén.
A Comparison osztály az elsődleges API belépési pont, amely végrehajtja a könyvtárak összehasonlítását és generálja a jelentést.
Tedd a hívást try‑with‑resources blokkba (vagy használd a Comparison objektum close metódusát), hogy minden fájlkezelő gyorsan felszabaduljon, különösen ezrek fájljának feldolgozásakor.
Haladó konfigurációs beállítások
Az alap beállítás a legtöbb esetben működik, de a valós projektek gyakran finomhangolt viselkedést igényelnek.
Kimeneti formátumok testreszabása
A GroupDocs.Comparison exportálhat jelentéseket PDF, DOCX vagy egyszerű HTML formátumban. A formátum váltása olyan egyszerű, mint a compare hívásban a fájlkiterjesztés módosítása.
Fájlok és könyvtárak szűrése
Ha csak bizonyos fájltípusok érdekelnek (pl. .java és .xml), adj meg egy szűrő predikátumot, amely kihagyja a nem releváns fájlokat, és drámaian javítja a teljesítményt.
comparison.setFileFilter(path -> path.toString().endsWith(".java") || path.toString().endsWith(".xml"));
Gyakori problémák és megoldások
Tekintsük át a valószínűleg felmerülő problémákat (mert Murphy törvénye a kódolásra is érvényes).
Probléma 1: OutOfMemoryError nagy könyvtáraknál
Közvetlen válasz: Növeld a JVM heap méretét (-Xmx4g vagy nagyobb) és engedélyezd a streaming módot a Comparison beállításokban, hogy a fájlokat sorban dolgozd fel, ahelyett, hogy mindet memóriába töltenéd.
Tízezer fájlt tartalmazó könyvtárak esetén az alapértelmezett memória‑alapú megközelítés kimerítheti a heapet. A streaming mód igény szerint olvassa be a fájlokat, így a memóriahasználat 200 MB alatt marad még 10 000 fájlos futásoknál is.
Probléma 2: FileNotFoundException a helyes útvonalak ellenére
Közvetlen válasz: Ellenőrizd, hogy a Java folyamatnak olvasási jogosultsága van-e a forráskönyvtárakhoz és írási jogosultsága a kimeneti mappához; továbbá győződj meg róla, hogy az útvonalban lévő szóközök vagy speciális karakterek megfelelően vannak-e escape‑elve.
A gyakori okok közé tartozik az operációs rendszer szintű ACL korlátozások, a hitelesítést igénylő hálózati megosztások, valamint a Unicode karakterek, amelyeket explicit módon kell kezelni a java.nio.file.Paths segítségével.
Probléma 3: Az összehasonlítás örökké tart
Közvetlen válasz: Alkalmazz fájlszűrőket a nagy bináris eszközök kizárásához, engedélyezd a több szálas feldolgozást a független alkönyvtárakhoz, és figyeld a haladást egy callback hallgatóval, hogy korán azonosítsd a szűk keresztmetszeteket.
A részkönyvtárak párhuzamos összehasonlítása akár 70 %-kal is csökkentheti a futási időt egy 8‑magos szerveren, míg a progress callback egyszerű konzolos előrehaladási sávot biztosít a hosszú feladatokhoz.
Teljesítményoptimalizálás nagy‑léptékű összehasonlításokhoz
Amikor több ezer fájlt tartalmazó könyvtárakkal dolgozol, a teljesítmény kritikus. Íme, hogyan optimalizáld:
Memóriakezelés legjobb gyakorlatai
A ComparisonOptions osztály lehetővé teszi a összehasonlítási folyamat viselkedésének konfigurálását, például a streaming mód engedélyezését, fájlméret‑korlátok beállítását és a kimeneti formátumok választását.
- Használd a streaming módot (
ComparisonOptions.setUseStreaming(true)). - Állítsd be a feldolgozott fájlok maximális méretét (
setMaxFileSize(200 * 1024 * 1024)) 200 MB‑ra. - Zárd le explicit módon a
Comparisonobjektumot minden futás után.
Kötetes feldolgozási stratégia
Oszd fel a hatalmas könyvtárfát logikai kötegekre (pl. modul vagy dátumtartomány szerint), és futtasd őket sorban. Ez megakadályozza, hogy a JVM egyszerre egynél több köteget tartson a memóriában.
Párhuzamos feldolgozás független könyvtárakhoz
Ha több könyvtárpárt kell összehasonlítani (pl. éjszakai build-ek több mikroszolgáltatáshoz), indíts külön Comparison példányokat egy szálkészletben. Minden szál a saját párjával dolgozik, kihasználva az összes CPU magot.
Valós példák és iparági alkalmazások
A könyvtárak összehasonlítása nem csak fejlesztői eszköz — iparágak széles körében használják üzletkritikus folyamatokhoz:
Szoftverfejlesztés és DevOps
Release menedzsment: A telepítés előtt hasonlítsd össze a staging és a production mappákat, hogy elkapd a konfigurációs eltéréseket. A HTML jelentés csatolható egy pull‑requesthez a stakeholder‑ek átnézéséhez.
Pénzügy és megfelelőség
Audit nyomvonal karbantartása: Pénzügyi intézmények a könyvtárak összehasonlítását használják a dokumentumváltozások nyomon követésére a szabályozási megfelelés érdekében, biztosítva, hogy minden módosítás naplózott és archivált legyen.
Adatkezelés és ETL folyamatok
Adatintegritás ellenőrzése: Tömeges adatátvitel után futtass könyvtár-összehasonlítást, hogy garantáld, minden forrásfájl helyesen került a cél adat-tóba.
Tartalomkezelés és kiadás
Verziókezelés nem‑technikai csapatok számára: A marketing csapatok összehasonlíthatják egy weboldal asset mappájának két verzióját Git ismerete nélkül, egyértelmű vizuális diffet kapva.
Haladó tippek és legjobb gyakorlatok
Miután a könyvtárak összehasonlításával dolgoztál termelési környezetben, íme néhány keményen megtanult lecke:
Naplózás és monitorozás
Integráld az SLF4J‑t egy forgó fájl appenderrel, hogy rögzítse a kezdési‑időt, befejezési‑időt, a feldolgozott fájlok számát és minden kivételt. Ez a napló felbecsülhetetlen értékű a szakaszos hibák vizsgálatakor.
Hibakezelés és rugalmasság
Tedd a compare hívást egy újrapróbálkozási blokkba, amely elkapja az átmeneti I/O hibákat (pl. hálózati zavarok a csatolt meghajtókon), és a hibát legfeljebb háromszor újra végrehajtja a leállítás előtt.
Konfigurációkezelés
Externalizáld az összes útvonalat, kimeneti formátumot és teljesítmény‑flageket egy application.yml vagy properties fájlba. Ez lehetővé teszi az üzemeltető csapatok számára a beállítások finomhangolását a JAR újrafordítása nélkül.
Platform‑független útvonalkezelés
Mindig építs útvonalakat java.nio.file.Paths.get(...)‑vel, és használj File.separator‑t a karakterláncok összefűzésénél. Ez elkerüli a hibákat, amikor Windows (\) környezetből Linux (/) környezetbe váltasz.
Időbélyegek figyelmen kívül hagyása, ha nem fontosak
Ha csak a tartalomváltozások számítanak, állítsd be a CompareOptions.setIgnoreMetadata(true)‑t. Ez megakadályozza a hamis pozitív eredményeket, amelyeket a másolt fájlok automatikus időbélyeg‑frissítése okoz.
Gyakori telepítési problémák hibaelhárítása
Fejlesztésben működik, produkcióban hibás
Közvetlen válasz: Ellenőrizd az eset‑érzékenység különbségeket (Windows vs Linux), a fájlrendszer jogosultságait, és cseréld le a hard‑coded útvonal‑elválasztókat a File.separator‑re.
A termelési szerverek gyakran Linuxon futnak, ahol a myFile.txt és a MyFile.txt különböző. Használd a Path API‑kat a kis‑nagybetűk normalizálásához, hogy elkerüld a véletlen eltéréseket.
Inkonzisztens eredmények
Közvetlen válasz: Győződj meg róla, hogy a összehasonlítás futása közben semmilyen külső folyamat nem módosítja a fájlokat, és állítsd be a CompareOptions‑t, hogy figyelmen kívül hagyja az időbélyegeket, ha azok hamis eltéréseket okoznak.
A összehasonlítás futtatása csak‑olvasású pillanatfelvételen (pl. csatolt kötet pillanatfelvétel) garantálja a determinisztikus eredményeket.
Gyakran ismételt kérdések
Q: Hogyan kezeljek olyan könyvtárakat, amelyek millió fájlt tartalmaznak?
A: Kombináld a kötegelt feldolgozást, növeld a JVM heap méretét (-Xmx8g vagy nagyobb), engedélyezd a streaming módot, és futtasd a részkönyvtár-összehasonlításokat párhuzamosan. A Kötetes feldolgozási stratégia és a Párhuzamos feldolgozás szakaszok kész mintákat biztosítanak.
Q: Hasonlíthatok-e össze különböző szervereken lévő könyvtárakat?
A: Igen, de a hálózati késleltetés uralja a futási időt. A legjobb teljesítmény érdekében először másold le a távoli könyvtárat helyi gépre, vagy csatold a távoli megosztást megfelelő I/O sávszélességgel, mielőtt meghívod az összehasonlítást.
Q: Mely fájlformátumokat támogatja a GroupDocs.Comparison?
A: A GroupDocs.Comparison több mint 70 formátumot támogat, beleértve a DOC/DOCX, PDF, PPT/PPTX, XLS/XLSX, TXT, HTML, XML, CSV és a gyakori képtípusokat (PNG, JPEG, BMP). Lásd a hivatalos dokumentációt a legfrissebb listáért.
Q: Hogyan integrálhatom ezt az összehasonlítást egy CI/CD pipeline-ba?
A: Csomagold az összehasonlítási logikát egy futtatható JAR‑ba vagy Maven pluginba, majd hívd meg build lépésként Jenkins‑ben, GitHub Actions‑ban, Azure Pipelines‑ban vagy GitLab CI‑ben. Exportáld a HTML jelentést build‑artifactként a további átnézéshez.
Q: Lehet-e testreszabni a HTML jelentés megjelenését?
A: A beépített HTML sablon rögzített, de a generált fájlt utólag feldolgozhatod – egyedi CSS‑t vagy JavaScript‑et injektálva – hogy megfeleljen a vállalati arculatnak vagy interaktív elemeket adjon hozzá.
Utoljára frissítve: 2026-08-09
Tesztelve: GroupDocs.Comparison 25.2 (Java)
Szerző: 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);