Confronta documenti Word C# con confronto tramite stream in .NET

Introduzione

Se hai bisogno di confrontare documenti Word c# in un’applicazione .NET mantenendo un basso utilizzo della memoria, sei nel posto giusto. Il confronto basato su file tradizionale carica l’intero documento in RAM, il che diventa rapidamente un collo di bottiglia per file Word di grandi dimensioni o scenari cloud‑native in cui hai solo uno stream. Questo tutorial ti mostra, passo dopo passo, come eseguire il confronto di documenti basato su stream utilizzando GroupDocs.Comparison, completo di esempi reali, consigli sulle prestazioni e suggerimenti per la risoluzione dei problemi.

Risposte rapide

  • Quale libreria gestisce il confronto tramite stream? GroupDocs.Comparison per .NET.
  • Posso confrontare file Word direttamente da un MemoryStream? Sì – basta passare lo stream al comparatore.
  • È necessaria una licenza per la produzione? Assolutamente; una licenza valida di GroupDocs.Comparison rimuove le filigrane.
  • Quali versioni .NET sono supportate? .NET Framework 4.6.1+, .NET Core 2.0+, .NET 5/6/7.
  • Il supporto async è integrato? Non nativamente, ma è possibile avvolgere le chiamate in Task.Run per un comportamento async di base.

Cos’è il confronto di documenti basato su stream?

La classe Comparer in GroupDocs.Comparison legge i dati del documento da qualsiasi implementazione di Stream, consentendo il confronto senza mai scrivere il file su disco. Questo la rende ideale per l’archiviazione cloud, l’elaborazione di file di grandi dimensioni e i servizi web ad alta concorrenza.

Perché utilizzare il confronto basato su stream per confrontare documenti Word C#?

Il confronto basato su stream riduce la pressione sulla memoria elaborando i dati a blocchi anziché caricare l’intero file. GroupDocs.Comparison supporta oltre 50 formati di input e output — inclusi DOCX, PDF, PPTX e XLSX — e può gestire documenti di centinaia di pagine senza esaurire la RAM del server. L’approccio si allinea perfettamente con Azure Blob, AWS S3 o qualsiasi archiviazione basata su HTTP dove si riceve uno Stream anziché un percorso file fisico.

Prerequisiti

  • GroupDocs.Comparison per .NET (Versione 25.4.0 o successiva) – supporta oltre 50 formati.
  • .NET Framework 4.6.1+ o .NET Core 2.0+ (inclusi .NET 5/6/7).
  • Un IDE con supporto C# (Visual Studio, VS Code o Rider).
  • Conoscenza di base degli stream C# (FileStream, MemoryStream) e delle istruzioni using.

Configurazione di GroupDocs.Comparison per .NET

Passaggi di installazione

Utilizzo della console di NuGet Package Manager

Install-Package GroupDocs.Comparison -Version 25.4.0
Install-Package GroupDocs.Comparison -Version 25.4.0

Utilizzo di .NET CLI

dotnet add package GroupDocs.Comparison --version 25.4.0
dotnet add package GroupDocs.Comparison --version 25.4.0

Suggerimento professionale: Blocca il numero di versione per evitare modifiche incompatibili inaspettate quando appare una nuova release principale.

Configurazione della licenza (Importante!)

GroupDocs.Comparison richiede una licenza per l’uso in produzione. Puoi iniziare con una prova gratuita, ottenere una licenza temporanea per lavori proof‑of‑concept, o acquistare una licenza completa per distribuzioni illimitate. Visita GroupDocs Purchase per i dettagli.

Inizializzazione di base della licenza

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();

Ora sei pronto a confrontare documenti da qualsiasi sorgente stream.

Come confrontare documenti Word C# usando gli stream?

Carica i file Word di origine e destinazione come stream, passali al Comparer e scrivi il risultato in uno stream di output. Il flusso completo è illustrato di seguito.

Passo 1: Preparare gli stream di origine, destinazione e output

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));
}

Spiegazione:

  • File.OpenRead crea stream di sola lettura per i due file Word.
  • File.Create apre uno stream di sola scrittura dove verrà salvato il risultato del confronto.
  • Le istruzioni using garantiscono che ogni stream venga eliminato non appena il blocco termina, prevenendo blocchi di file e perdite di memoria.

Passo 2: Inizializzare il Comparer con lo stream di origine

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();
}

Ancora di definizione: La classe Comparer è il componente centrale di GroupDocs.Comparison che orchestra il caricamento, l’analisi e la generazione delle differenze tra due o più stream di documenti.

Passo 3: Aggiungere stream di destinazione

comparer.Add(targetStream);
// If you must reuse a stream, reset its position
stream.Position = 0;

Puoi chiamare Add più volte per confrontare l’origine con diverse versioni di destinazione in un’unica esecuzione.

Passo 4: Eseguire il confronto e scrivere il risultato

ComparisonResult rappresenta il risultato di un confronto, contenente il documento delle differenze e i relativi metadati.

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();
}

Cosa succede qui?

  • Compare() elabora entrambi gli stream, rileva inserimenti, cancellazioni e modifiche di formattazione, e restituisce un oggetto ComparisonResult.
  • Save() scrive il documento di confronto evidenziato nello resultStream creato in precedenza.

Gestione avanzata degli stream

Lavorare con MemoryStream (ad esempio file caricati via HTTP)

Quando la tua applicazione riceve un caricamento di file, tipicamente ottieni un MemoryStream. La stessa API funziona senza modifiche:

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
}

Perché è importante: L’uso di MemoryStream elimina la necessità di file temporanei su disco, migliorando le prestazioni nei servizi web senza stato e negli ambienti containerizzati.

Problemi comuni e soluzioni

Problema #1: Posizione dello stream non reimpostata

Problema: Se uno stream è stato letto in precedenza (ad esempio per la convalida), la sua posizione potrebbe essere alla fine, causando al comparatore di leggere zero byte.
Soluzione: Reimposta la posizione prima di passare lo stream:

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
}

Problema #2: Dimenticare di eliminare gli stream

Problema: Gli stream non eliminati mantengono aperti i handle dei file, provocando errori “file in uso”.
Soluzione: Avvolgi sempre gli stream in blocchi using o chiama esplicitamente Dispose(), come mostrato nell’implementazione principale.

Problema #3: Utilizzare stream non ricercabili

Problema: Alcuni stream di rete (ad esempio NetworkStream) non supportano il seeking, che il comparatore potrebbe richiedere.
Soluzione: Copia prima lo stream non ricercabile in 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");
    }
}

Best practice sulle prestazioni

Ottimizzare l’uso della memoria

  • Ottimizzazione della dimensione del buffer: Per documenti più grandi di 50 MB, aumenta la dimensione del buffer interno a 1 MB per ridurre i cicli di lettura‑scrittura.
  • I/O asincrono: In ASP.NET Core, utilizza le API di file asincrone (FileStream.OpenReadAsync) per liberare i thread durante le operazioni I/O.

Monitorare il consumo di risorse

  • Contatori di prestazioni: Monitora Process.PrivateMemorySize64 prima e dopo il confronto per verificare l’impatto sulla memoria.
  • Benchmarking: Esegui test dotnet benchmark confrontando approcci basati su file vs. stream; le esecuzioni basate su stream sono tipicamente 20‑30 % più veloci su file DOCX di 200 pagine.

Controllo della concorrenza

  • Sistema di coda: Limita i confronti simultanei al numero di core CPU per evitare crash per esaurimento della memoria.
  • Eliminare presto: Rilascia gli stream di origine e destinazione subito dopo il ritorno di Compare(); lo stream di risultato può rimanere aperto finché non lo scrivi al client.

Casi d’uso reali

Caso d’uso 1: Revisione documenti in applicazione web

Una piattaforma SaaS consente agli utenti di caricare due versioni di un contratto per una revisione affiancata. I file caricati arrivano come oggetti IFormFile, che vengono convertiti in MemoryStream e confrontati istantaneamente, restituendo un DOCX scaricabile con le modifiche tracciate.

Caso d’uso 2: Elaborazione batch dallo storage cloud

Una Azure Function si attiva su nuovi blob in un contenitore, legge ogni blob come stream, lo confronta con una versione di riferimento memorizzata in un altro contenitore e scrive il risultato del confronto in un contenitore “results”.

Caso d’uso 3: Integrazione con il controllo di versione

Una pipeline DevOps estrae file Word da un repository Git, li trasmette a GroupDocs.Comparison e genera un report delle differenze che viene allegato all’artefatto di build per gli auditor.

Guida alla risoluzione dei problemi

ProblemaCausa probabileSoluzione
“Lo stream non supporta la lettura”È stato passato uno stream di sola scrittura (ad esempio File.OpenWrite)Usa File.OpenRead o assicurati che CanRead sia true.
“Riferimento a oggetto non impostato su un’istanza di un oggetto”Lo stream era null o è stato eliminato prima del confrontoVerifica l’inizializzazione dello stream e mantieni il blocco using aperto fino a dopo Compare().
Prestazioni scarse su file > 100 MBLa dimensione predefinita del buffer è troppo piccola, o ci sono troppe attività concorrentiAumenta la dimensione del buffer, limita la concorrenza e profila con dotMemory.
Errori di licenza in produzioneFile di licenza mancante o percorso erratoPosiziona GroupDocs.Comparison.lic nella root dell’applicazione e chiama SetLicense all’inizio dell’avvio.
Dati stream corrottiInterruzione di rete durante il download dallo storage cloudConvalida la lunghezza e il checksum dello stream prima del confronto.

Opzioni di configurazione avanzate

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();
    }
}

Ancora di definizione: CompareOptions è un oggetto di configurazione che consente di controllare lo stile visivo, la protezione con password e quali tipi di modifiche vengono segnalati.

Integrazione con i framework .NET più popolari

Integrazione 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
        };
    }
}

Integrazione 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);
}

Conclusione

Il confronto di documenti basato su stream in .NET ti offre un modo efficiente in termini di memoria, pronto per il cloud e ad alte prestazioni per confrontare file Word. Sfruttando la classe Comparer di GroupDocs.Comparison, puoi lavorare direttamente con oggetti Stream, evitare file temporanei e scalare a migliaia di confronti simultanei. Segui le best practice illustrate sopra—corretta eliminazione degli stream, ottimizzazione del buffer e licenza adeguata—per garantire un’implementazione di produzione solida.

Risorse


Ultimo aggiornamento: 2026-05-31
Testato con: GroupDocs.Comparison 25.4.0 per .NET
Autore: 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
            }
        }
    }
}

Tutorial correlati