Comparer des documents Word C# avec la comparaison de flux dans .NET
Introduction
Si vous devez compare word documents c# dans une application .NET tout en maintenant une faible consommation de mémoire, vous êtes au bon endroit. La comparaison basée sur les fichiers force le chargement complet du document en RAM, ce qui devient rapidement un goulot d’étranglement pour les gros fichiers Word ou les scénarios cloud‑native où vous ne disposez que d’un flux. Ce tutoriel vous montre, étape par étape, comment effectuer une comparaison de documents basée sur les flux en utilisant GroupDocs.Comparison, avec des exemples concrets, des conseils de performance et des solutions de dépannage.
Réponses rapides
- Quelle bibliothèque gère la comparaison de flux ? GroupDocs.Comparison for .NET.
- Puis-je comparer des fichiers Word directement à partir d’un MemoryStream ? Oui – il suffit de passer le flux au comparateur.
- Ai-je besoin d’une licence pour la production ? Absolument ; une licence valide de GroupDocs.Comparison supprime les filigranes.
- Quelles versions de .NET sont prises en charge ? .NET Framework 4.6.1+, .NET Core 2.0+, .NET 5/6/7.
- Le support async est‑il intégré ? Pas nativement, mais vous pouvez encapsuler les appels dans
Task.Runpour un comportement async de base.
Qu’est-ce que la comparaison de documents basée sur les flux ?
La classe Comparer de GroupDocs.Comparison lit les données du document à partir de n’importe quelle implémentation de Stream, permettant la comparaison sans jamais écrire le fichier sur le disque. Cela la rend idéale pour le stockage cloud, le traitement de gros fichiers et les services web à haute concurrence.
Pourquoi utiliser la comparaison basée sur les flux pour comparer des documents Word C# ?
La comparaison basée sur les flux réduit la pression sur la mémoire en traitant les données par morceaux plutôt qu’en chargeant le fichier complet. GroupDocs.Comparison prend en charge plus de 50 formats d’entrée et de sortie — y compris DOCX, PDF, PPTX et XLSX — et peut gérer des documents de plusieurs centaines de pages sans épuiser la RAM du serveur. Cette approche s’aligne également parfaitement avec Azure Blob, AWS S3 ou tout stockage basé sur HTTP où vous recevez un Stream au lieu d’un chemin de fichier physique.
Prérequis
- GroupDocs.Comparison for .NET (Version 25.4.0 ou ultérieure) – prend en charge plus de 50 formats.
- .NET Framework 4.6.1+ ou .NET Core 2.0+ (incluant .NET 5/6/7).
- Un IDE avec support C# (Visual Studio, VS Code ou Rider).
- Connaissances de base des flux C# (
FileStream,MemoryStream) et des instructionsusing.
Configuration de GroupDocs.Comparison pour .NET
Étapes d’installation
Using NuGet Package Manager Console
Install-Package GroupDocs.Comparison -Version 25.4.0
Install-Package GroupDocs.Comparison -Version 25.4.0
Using .NET CLI
dotnet add package GroupDocs.Comparison --version 25.4.0
dotnet add package GroupDocs.Comparison --version 25.4.0
Astuce pro : Épinglez le numéro de version pour éviter les changements majeurs inattendus lorsqu’une nouvelle version majeure apparaît.
Configuration de la licence (Important !)
GroupDocs.Comparison nécessite une licence pour une utilisation en production. Vous pouvez commencer avec un essai gratuit, obtenir une licence temporaire pour un proof‑of‑concept, ou acheter une licence complète pour des déploiements illimités. Consultez Achat GroupDocs pour plus de détails.
Basic License Initialization
var license = new GroupDocs.Comparison.License();
license.SetLicense("GroupDocs.Comparison.lic");
using GroupDocs.Comparison;
using System.IO;
// This is your foundation for all comparisons
Comparer comparer = new Comparer();
Vous êtes maintenant prêt à comparer des documents à partir de n’importe quelle source de flux.
Comment comparer des documents Word C# en utilisant des flux ?
Chargez vos fichiers Word source et cible en tant que flux, transmettez‑les au Comparer et écrivez le résultat dans un flux de sortie. Le flux complet est illustré ci‑dessous.
Étape 1 : préparer les flux source, cible et de sortie
using (var sourceStream = File.OpenRead("Original.docx"))
using (var targetStream = File.OpenRead("Revised.docx"))
using (var resultStream = File.Create("ComparisonResult.docx"))
{
// Comparison logic goes here
}
string sourceDocumentPath = Path.Combine("YOUR_DOCUMENT_DIRECTORY", "source.docx");
string targetDocumentPath = Path.Combine("YOUR_DOCUMENT_DIRECTORY", "target.docx");
string outputDirectory = Path.Combine("YOUR_OUTPUT_DIRECTORY", ".");
string outputFileName = Path.Combine(outputDirectory, "comparison_result.docx");
using (Comparer comparer = new Comparer(File.OpenRead(sourceDocumentPath)))
{
// Step 2: Add the Target Document
comparer.Add(File.OpenRead(targetDocumentPath));
// Step 3: Perform Comparison and Save Results
comparer.Compare(File.Create(outputFileName));
}
Explication :
File.OpenReadcrée des flux en lecture seule pour les deux fichiers Word.File.Createouvre un flux en écriture seule où le résultat de la comparaison sera enregistré.- Les instructions
usinggarantissent que chaque flux est libéré dès la fin du bloc, évitant les verrous de fichiers et les fuites de mémoire.
Étape 2 : initialiser le Comparer avec le flux source
var comparer = new GroupDocs.Comparison.Comparer(sourceStream);
// Example: Comparing documents from byte arrays
byte[] sourceBytes = GetDocumentFromDatabase(sourceId);
byte[] targetBytes = GetDocumentFromDatabase(targetId);
using (var sourceStream = new MemoryStream(sourceBytes))
using (var targetStream = new MemoryStream(targetBytes))
using (var outputStream = new MemoryStream())
using (var comparer = new Comparer(sourceStream))
{
comparer.Add(targetStream);
comparer.Compare(outputStream);
// Now you can work with the result in memory
byte[] resultBytes = outputStream.ToArray();
}
Ancre de définition : La classe Comparer est le composant central de GroupDocs.Comparison qui orchestre le chargement, l’analyse et la génération des différences entre deux flux de documents ou plus.
Étape 3 : ajouter le(s) flux cible(s)
comparer.Add(targetStream);
// If you must reuse a stream, reset its position
stream.Position = 0;
Vous pouvez appeler Add plusieurs fois pour comparer la source à plusieurs versions cibles en une seule exécution.
Étape 4 : exécuter la comparaison et écrire le résultat
ComparisonResult représente le résultat d’une comparaison, contenant le document de différences et les métadonnées associées.
var result = comparer.Compare();
result.Save(resultStream);
// Good - automatic disposal
using (var stream = File.OpenRead(path))
{
// Use stream
}
// Also good - manual disposal
var stream = File.OpenRead(path);
try
{
// Use stream
}
finally
{
stream?.Dispose();
}
Que se passe-t-il ici ?
Compare()traite les deux flux, détecte les insertions, suppressions et changements de formatage, et renvoie un objetComparisonResult.Save()écrit le document de comparaison mis en évidence dans leresultStreamque vous avez créé précédemment.
Gestion avancée des flux
Utilisation de MemoryStream (par ex., fichiers téléchargés via HTTP)
Lorsque votre application reçoit un téléchargement de fichier, vous obtenez généralement un MemoryStream. La même API fonctionne sans modification :
var uploadedSource = new MemoryStream(await httpRequest.Form.Files[0].OpenReadStream().ReadAllBytesAsync());
var uploadedTarget = new MemoryStream(await httpRequest.Form.Files[1].OpenReadStream().ReadAllBytesAsync());
var comparer = new GroupDocs.Comparison.Comparer(uploadedSource);
comparer.Add(uploadedTarget);
var result = comparer.Compare();
await result.SaveAsync(response.Body);
if (stream.CanSeek)
{
// Safe to use Position and Length properties
}
Pourquoi c’est important : L’utilisation de MemoryStream élimine le besoin de fichiers temporaires sur le disque, ce qui améliore les performances dans les services web sans état et les environnements conteneurisés.
Pièges courants et solutions
Écueil #1 : la position du flux n’est pas réinitialisée
Problème : Si un flux a été lu auparavant (par ex., pour validation), sa position peut être à la fin, ce qui fait que le comparateur lit zéro octet.
Solution : Réinitialisez la position avant de transmettre le flux :
sourceStream.Position = 0;
targetStream.Position = 0;
// Example of async file reading (though GroupDocs.Comparison doesn't support async yet)
var sourceBytes = await File.ReadAllBytesAsync(sourcePath);
using (var sourceStream = new MemoryStream(sourceBytes))
{
// Comparison logic
}
Écueil #2 : oublier de libérer les flux
Problème : Les flux non libérés conservent les poignées de fichiers ouvertes, entraînant des erreurs « fichier en cours d’utilisation ».
Solution : Enveloppez toujours les flux dans des blocs using ou appelez explicitement Dispose(), comme illustré dans l’implémentation principale.
Écueil #3 : utilisation de flux non recherchables
Problème : Certains flux réseau (par ex., NetworkStream) ne supportent pas la recherche, ce dont le comparateur peut avoir besoin.
Solution : Copiez d’abord le flux non recherchable dans un MemoryStream :
var seekableStream = new MemoryStream();
await nonSeekableStream.CopyToAsync(seekableStream);
seekableStream.Position = 0;
[HttpPost]
public async Task<IActionResult> CompareDocuments(IFormFile sourceFile, IFormFile targetFile)
{
using (var sourceStream = sourceFile.OpenReadStream())
using (var targetStream = targetFile.OpenReadStream())
using (var outputStream = new MemoryStream())
using (var comparer = new Comparer(sourceStream))
{
comparer.Add(targetStream);
comparer.Compare(outputStream);
return File(outputStream.ToArray(), "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "comparison.docx");
}
}
Meilleures pratiques de performance
Optimiser l’utilisation de la mémoire
- Ajustement de la taille du tampon : Pour les documents supérieurs à 50 Mo, augmentez la taille du tampon interne à 1 Mo pour réduire les cycles de lecture‑écriture.
- E/S asynchrones : Dans ASP.NET Core, utilisez les API de fichiers asynchrones (
FileStream.OpenReadAsync) pour libérer les threads pendant les I/O.
Surveiller la consommation de ressources
- Compteurs de performance : Suivez
Process.PrivateMemorySize64avant et après la comparaison pour vérifier l’impact mémoire. - Benchmarking : Exécutez des tests
dotnet benchmarkcomparant les approches basées sur les fichiers et sur les flux ; les exécutions basées sur les flux sont généralement 20‑30 % plus rapides sur des fichiers DOCX de 200 pages.
Contrôle de la concurrence
- Système de file d’attente : Limitez les comparaisons simultanées au nombre de cœurs CPU pour éviter les plantages de mémoire.
- Libération précoce : Libérez les flux source et cible immédiatement après le retour de
Compare(); le flux de résultat peut rester ouvert jusqu’à ce que vous l’écriviez au client.
Cas d’utilisation réels
Cas d’utilisation 1 : révision de documents d’application web
Une plateforme SaaS permet aux utilisateurs de télécharger deux versions d’un contrat pour une révision côte à côte. Les fichiers téléchargés arrivent sous forme d’objets IFormFile, qui sont convertis en MemoryStream et comparés instantanément, renvoyant un DOCX téléchargeable avec les modifications suivies.
Cas d’utilisation 2 : traitement par lots depuis le stockage cloud
Une Azure Function se déclenche sur les nouveaux blobs d’un conteneur, lit chaque blob en tant que flux, le compare à une version de référence stockée dans un autre conteneur, puis écrit le résultat de la comparaison dans un conteneur « results ».
Cas d’utilisation 3 : intégration du contrôle de version
Un pipeline DevOps extrait les fichiers Word d’un dépôt Git, les transmet sous forme de flux à GroupDocs.Comparison, et génère un rapport de différences qui est joint à l’artefact de build pour les auditeurs.
Guide de dépannage
| Problème | Cause probable | Solution |
|---|---|---|
| “Stream does not support reading” | Flux en écriture seule passé (par ex., File.OpenWrite) | Utilisez File.OpenRead ou assurez‑vous que CanRead est vrai. |
| “Object reference not set to an instance of an object” | Le flux était nul ou libéré avant la comparaison | Vérifiez l’initialisation du flux et maintenez le bloc using ouvert jusqu’après Compare(). |
| Poor performance on 100 MB+ files | Taille de tampon par défaut trop petite, ou trop de tâches concurrentes | Augmentez la taille du tampon, limitez la concurrence, et profilez avec dotMemory. |
| Licensing errors in production | Fichier de licence manquant ou chemin incorrect | Placez GroupDocs.Comparison.lic à la racine de l’application et appelez SetLicense tôt au démarrage. |
| Corrupted stream data | Interruption réseau lors du téléchargement depuis le stockage cloud | Validez la longueur du flux et la somme de contrôle avant la comparaison. |
Options de configuration avancées
var options = new CompareOptions
{
HighlightColor = Color.Yellow,
ShowDeletedContent = true,
ShowInsertedContent = true,
StyleChangeDetection = true,
Password = "optionalPassword"
};
var comparer = new GroupDocs.Comparison.Comparer(sourceStream, options);
public async Task<byte[]> CompareCloudDocuments(string sourceUrl, string targetUrl)
{
using (var httpClient = new HttpClient())
using (var sourceStream = await httpClient.GetStreamAsync(sourceUrl))
using (var targetStream = await httpClient.GetStreamAsync(targetUrl))
using (var outputStream = new MemoryStream())
using (var comparer = new Comparer(sourceStream))
{
comparer.Add(targetStream);
comparer.Compare(outputStream);
return outputStream.ToArray();
}
}
Ancre de définition : CompareOptions est un objet de configuration qui vous permet de contrôler le style visuel, la protection par mot de passe, et quels types de modifications sont signalés.
Intégration avec les frameworks .NET populaires
Intégration ASP.NET Core
public async Task<IActionResult> Compare(IFormFile source, IFormFile target)
{
using var sourceStream = new MemoryStream();
using var targetStream = new MemoryStream();
await source.CopyToAsync(sourceStream);
await target.CopyToAsync(targetStream);
sourceStream.Position = 0;
targetStream.Position = 0;
var comparer = new GroupDocs.Comparison.Comparer(sourceStream);
comparer.Add(targetStream);
var result = comparer.Compare();
var output = new MemoryStream();
result.Save(output);
output.Position = 0;
return File(output, "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"ComparisonResult.docx");
}
public DocumentComparisonResult CompareDocumentVersions(int documentId, int version1, int version2)
{
var doc1Stream = GetDocumentVersionStream(documentId, version1);
var doc2Stream = GetDocumentVersionStream(documentId, version2);
using (doc1Stream)
using (doc2Stream)
using (var outputStream = new MemoryStream())
using (var comparer = new Comparer(doc1Stream))
{
comparer.Add(doc2Stream);
comparer.Compare(outputStream);
return new DocumentComparisonResult
{
ComparisonData = outputStream.ToArray(),
ComparedAt = DateTime.UtcNow,
SourceVersion = version1,
TargetVersion = version2
};
}
}
Intégration Windows Forms / WPF
var openFileDialog = new OpenFileDialog { Filter = "Word files (*.docx)|*.docx" };
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
using var source = File.OpenRead(openFileDialog.FileName);
// Repeat for target, then compare as shown earlier
}
using (var comparer = new Comparer(sourceStream))
{
comparer.Add(targetStream);
var compareOptions = new CompareOptions
{
ShowDeletedContent = true,
ShowInsertedContent = true,
GenerateSummaryPage = true
};
comparer.Compare(outputStream, compareOptions);
}
Conclusion
La comparaison de documents basée sur les flux dans .NET vous offre une méthode efficace en mémoire, prête pour le cloud et haute performance pour comparer des fichiers Word. En tirant parti de la classe Comparer de GroupDocs.Comparison, vous pouvez travailler directement avec des objets Stream, éviter les fichiers temporaires et évoluer jusqu’à des milliers de comparaisons simultanées. Suivez les meilleures pratiques décrites ci‑dessus — libération correcte des flux, réglage du tampon et gestion de la licence — pour garantir une implémentation de production robuste.
Ressources
- Achat GroupDocs
- Documentation GroupDocs.Comparison
- Référence API
- Télécharger la dernière version
- Acheter une licence
- Essai gratuit
- Licence temporaire
- Support communautaire
Dernière mise à jour : 2026-05-31
Testé avec : GroupDocs.Comparison 25.4.0 for .NET
Auteur : GroupDocs
public class DocumentComparisonService
{
public async Task<ComparisonResult> CompareDocumentsAsync(Stream source, Stream target)
{
// Your comparison logic here
// This is where the earlier examples would fit
}
}
private void CompareButton_Click(object sender, EventArgs e)
{
using (var openFileDialog = new OpenFileDialog())
{
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
using (var stream = File.OpenRead(openFileDialog.FileName))
{
// Perform comparison
}
}
}
}