问题描述
处理 Office Open XML 文档(例如,自 Office 2007 发布以来由 Word、Excel 或 PowerPoint 创建的文档)时,您通常希望克隆或复制现有文档,然后对该副本进行更改,从而创建一个新文档.
在这种情况下,已经提出和回答了几个问题(有时是错误的或至少不是最佳的),这表明用户确实面临着问题.例如:
- 使用 OpenXml 和 C# 复制 Word 文档莉>
- Word OpenXml Word 发现无法读取的内容
- 打开XML SDK:打开 Word 模板并保存为不同的文件名
- 通过 OpenXML C# 复制时 docx 文档损坏
所以,问题是:
- 正确克隆或复制这些文档的可能方法是什么?
- 哪种方式最有效?
以下示例类展示了正确复制几乎任何文件并在 MemoryStream
或 FileStream 上返回副本的多种方法
然后您可以从中打开 WordprocessingDocument
(Word)、SpreadsheetDocument
(Excel) 或 PresentationDocument
(PowerPoint) 并制作任何内容更改,使用 Open XML SDK 和可选的 Open-XML-PowerTools.
使用 System.IO;命名空间 CodeSnippets.IO{//////这个类演示了多种方法来克隆存储在文件系统中的文件.///在所有情况下,源文件都存储在文件系统中.哪里返回类型///是一个 <see cref="MemoryStream"/>,目标文件将只存储在那个///.其中返回类型是 <see cref="FileStream"/>,///目标文件将存储在文件系统中并在该文件系统上打开///.///</总结>//////<see cref="MemoryStream"/>的内容样本返回的实例///可以将方法写入文件,如下所示://////var stream = ReadAllBytesToMemoryStream(sourcePath);///File.WriteAllBytes(destPath, stream.GetBuffer());//////你可以使用 <see cref="MemoryStream.GetBuffer"/>在 MemoryStream 的情况下///是使用 <see cref="MemoryStream()"/> 创建的或 <see cref="MemoryStream(int)"/>.///在其他情况下,您可以使用 <see cref="MemoryStream.ToArray"/>方法,其中///将内部缓冲区复制到一个新的字节数组.因此, GetBuffer() 应该有点///快点.///</备注>公共静态类 FileCloner{public static MemoryStream ReadAllBytesToMemoryStream(字符串路径){byte[] buffer = File.ReadAllBytes(path);var destStream = new MemoryStream(buffer.Length);destStream.Write(buffer, 0, buffer.Length);destStream.Seek(0, SeekOrigin.Begin);返回目标流;}public static MemoryStream CopyFileStreamToMemoryStream(字符串路径){使用 FileStream sourceStream = File.OpenRead(path);var destStream = new MemoryStream((int) sourceStream.Length);sourceStream.CopyTo(destStream);destStream.Seek(0, SeekOrigin.Begin);返回目标流;}公共静态文件流 CopyFileStreamToFileStream(string sourcePath, string destPath){使用 FileStream sourceStream = File.OpenRead(sourcePath);FileStream destStream = File.Create(destPath);sourceStream.CopyTo(destStream);destStream.Seek(0, SeekOrigin.Begin);返回目标流;}公共静态文件流 CopyFileAndOpenFileStream(string sourcePath, string destPath){File.Copy(sourcePath, destPath, true);返回新的 FileStream(destPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);}}}
在上述 Open XML-agnostic 方法之上,您还可以使用以下方法,例如,如果您已经打开了一个 OpenXmlPackage
,例如 WordprocessingDocument
、SpreadsheetDocument
或 PresentationDocument
:
public void DoWorkCloningOpenXmlPackage(){使用 WordprocessingDocument sourceWordDocument = WordprocessingDocument.Open(SourcePath, false);//Open XML SDK 中有多个 Clone() 方法的重载.//这一个将源文档克隆到给定的目标路径并//以读写模式打开它.使用 var wordDocument = (WordprocessingDocument) sourceWordDocument.Clone(DestPath, true);ChangeWordprocessingDocument(wordDocument);}
以上所有方法都可以正确克隆或复制文档.但最有效的方法是什么?
进入我们的基准测试,它使用 BenchmarkDotNet
NuGet 包:
使用系统;使用 System.Collections.Generic;使用 System.Diagnostics.CodeAnalysis;使用 System.IO;使用 System.Linq;使用 BenchmarkDotNet.Attributes;使用 CodeSnippets.IO;使用 CodeSnippets.OpenXml.Wordprocessing;使用 DocumentFormat.OpenXml.Packaging;使用 DocumentFormat.OpenXml.Wordprocessing;命名空间 CodeSnippets.Benchmarks.IO{公共类 FileClonerBenchmark{#region 设置和帮助程序private const string SourcePath = "Source.docx";private const string DestPath = "Destination.docx";[参数(1, 10, 100, 1000)]public static int ParagraphCount;[全局设置]public void GlobalSetup(){CreateTestDocument(SourcePath);CreateTestDocument(DestPath);}私有静态无效 CreateTestDocument(字符串路径){const string sentence = "敏捷的棕色狐狸跳过懒惰的狗.";string text = string.Join(" ", Enumerable.Range(0, 22).Select(i => sentence));IEnumerabletexts = Enumerable.Range(0, ParagraphCount).Select(i => text);使用 WordprocessingDocument 未使用 = WordprocessingDocumentFactory.Create(path, texts);}private static void ChangeWordprocessingDocument(WordprocessingDocument wordDocument){正文 body = wordDocument.MainDocumentPart.Document.Body;Text text = body.Descendants().First();text.Text = DateTimeOffset.UtcNow.Ticks.ToString();}#endregion#region 基准[基准(基线 = 真)]public void DoWorkUsingReadAllBytesToMemoryStream(){使用 MemoryStream destStream = FileCloner.ReadAllBytesToMemoryStream(SourcePath);使用 (WordprocessingDocument wordDocument = WordprocessingDocument.Open(destStream, true)){ChangeWordprocessingDocument(wordDocument);}File.WriteAllBytes(DestPath, destStream.GetBuffer());}[基准]public void DoWorkUsingCopyFileStreamToMemoryStream(){使用 MemoryStream destStream = FileCloner.CopyFileStreamToMemoryStream(SourcePath);使用 (WordprocessingDocument wordDocument = WordprocessingDocument.Open(destStream, true)){ChangeWordprocessingDocument(wordDocument);}File.WriteAllBytes(DestPath, destStream.GetBuffer());}[基准]public void DoWorkUsingCopyFileStreamToFileStream(){使用 FileStream destStream = FileCloner.CopyFileStreamToFileStream(SourcePath, DestPath);使用 WordprocessingDocument wordDocument = WordprocessingDocument.Open(destStream, true);ChangeWordprocessingDocument(wordDocument);}[基准]public void DoWorkUsingCopyFileAndOpenFileStream(){使用 FileStream destStream = FileCloner.CopyFileAndOpenFileStream(SourcePath, DestPath);使用 WordprocessingDocument wordDocument = WordprocessingDocument.Open(destStream, true);ChangeWordprocessingDocument(wordDocument);}[基准]public void DoWorkCloningOpenXmlPackage(){使用 WordprocessingDocument sourceWordDocument = WordprocessingDocument.Open(SourcePath, false);使用 var wordDocument = (WordprocessingDocument) sourceWordDocument.Clone(DestPath, true);ChangeWordprocessingDocument(wordDocument);}#endregion}}
上述基准测试运行如下:
使用 BenchmarkDotNet.Running;使用 CodeSnippets.Benchmarks.IO;命名空间 CodeSnippets.Benchmarks{公共静态类程序{public static void Main(){BenchmarkRunner.Run();}}}
我的机器上的结果是什么?哪种方法最快?
BenchmarkDotNet=v0.12.0,操作系统=Windows 10.0.18362Intel Core i7-7500U CPU 2.70GHz (Kaby Lake),1 个 CPU,4 个逻辑核心和 2 个物理核心.NET 核心 SDK=3.0.100[主机] : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), X64 RyuJITDefaultJob : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), X64 RyuJIT
|方法 |ParaCount |意思 |错误 |标准偏差 |中位数 |比率 ||--------------------------------------- |--------- |--------: |--------: |--------: |--------: |----: ||DoWorkUsingReadAllBytesToMemoryStream |1 |1.548 毫秒 |0.0298 毫秒 |0.0279 毫秒 |1.540 毫秒 |1.00 ||DoWorkUsingCopyFileStreamToMemoryStream |1 |1.561 毫秒 |0.0305 毫秒 |0.0271 毫秒 |1.556 毫秒 |1.01 ||DoWorkUsingCopyFileStreamToFileStream |1 |2.394 毫秒 |0.0601 毫秒 |0.1100 毫秒 |2.354 毫秒 |1.55 ||DoWorkUsingCopyFileAndOpenFileStream |1 |3.302 毫秒 |0.0657 毫秒 |0.0855 毫秒 |3.312 毫秒 |2.12 ||DoWorkCloningOpenXmlPackage |1 |4.567 毫秒 |0.1218 毫秒 |0.3591 毫秒 |4.557 毫秒 |3.13 ||||||||||DoWorkUsingReadAllBytesToMemoryStream |10 |1.737 毫秒 |0.0337 毫秒 |0.0361 毫秒 |1.742 毫秒 |1.00 ||DoWorkUsingCopyFileStreamToMemoryStream |10 |1.752 毫秒 |0.0347 毫秒 |0.0571 毫秒 |1.739 毫秒 |1.01 ||DoWorkUsingCopyFileStreamToFileStream |10 |2.505 毫秒 |0.0390 毫秒 |0.0326 毫秒 |2.500 毫秒 |1.44 ||DoWorkUsingCopyFileAndOpenFileStream |10 |3.532 毫秒 |0.0731 毫秒 |0.1860 毫秒 |3.455 毫秒 |2.05 ||DoWorkCloningOpenXmlPackage |10 |4.446 毫秒 |0.0880 毫秒 |0.1470 毫秒 |4.424 毫秒 |2.56 ||||||||||DoWorkUsingReadAllBytesToMemoryStream |100 |2.847 毫秒 |0.0563 毫秒 |0.0553 毫秒 |2.857 毫秒 |1.00 ||DoWorkUsingCopyFileStreamToMemoryStream |100 |2.865 毫秒 |0.0561 毫秒 |0.0786 毫秒 |2.868 毫秒 |1.02 ||DoWorkUsingCopyFileStreamToFileStream |100 |3.550 毫秒 |0.0697 毫秒 |0.0881 毫秒 |3.570 毫秒 |1.25 ||DoWorkUsingCopyFileAndOpenFileStream |100 |4.456 毫秒 |0.0877 毫秒 |0.0861 毫秒 |4.458 毫秒 |1.57 ||DoWorkCloningOpenXmlPackage |100 |5.958 毫秒 |0.1242 毫秒 |0.2727 毫秒 |5.908 毫秒 |2.10 ||||||||||DoWorkUsingReadAllBytesToMemoryStream |1000 |12.378 毫秒 |0.2453 毫秒 |0.2519 毫秒 |12.442 毫秒 |1.00 ||DoWorkUsingCopyFileStreamToMemoryStream |1000 |12.538 毫秒 |0.2070 毫秒 |0.1835 毫秒 |12.559 毫秒 |1.02 ||DoWorkUsingCopyFileStreamToFileStream |1000 |12.919 毫秒 |0.2457 毫秒 |0.2298 毫秒 |12.939 毫秒 |1.05 ||DoWorkUsingCopyFileAndOpenFileStream |1000 |13.728 毫秒 |0.2803 毫秒 |0.5196 毫秒 |13.652 毫秒 |1.11 ||DoWorkCloningOpenXmlPackage |1000 |16.868 毫秒 |0.2174 毫秒 |0.1927 毫秒 |16.801 毫秒 |1.37 |
事实证明,DoWorkUsingReadAllBytesToMemoryStream()
始终是最快的方法.但是,DoWorkUsingCopyFileStreamToMemoryStream()
的余量很容易带有误差余量.这意味着您应该尽可能在 MemoryStream
上打开 Open XML 文档以进行处理.如果您不必将生成的文档存储在您的文件系统中,这甚至比不必要地使用 FileStream
还要快得多.
无论在何处涉及输出 FileStream
,您都会看到更显着"的差异(请注意,如果您处理大量文档,则一毫秒可能会有所不同).并且您应该注意,使用 File.Copy()
实际上并不是一个好方法.
最后,使用 OpenXmlPackage.Clone()
方法或其覆盖之一被证明是最慢的方法.这是因为它涉及比仅仅复制字节更复杂的逻辑.但是,如果您获得的只是对 OpenXmlPackage
(或其子类之一)的引用,Clone()
方法及其覆盖是您的最佳选择.>
您可以在我的 CodeSnippets GitHub 存储库中找到完整的源代码.查看 CodeSnippets.Benchmark 项目和 FileCloner 类.
When working with Office Open XML documents, e.g., as created by Word, Excel, or PowerPoint since Office 2007 was released, you will often want to clone, or copy, an existing document and then make changes to that clone, thereby creating a new document.
Several questions have already been asked and answered (sometimes incorrectly or at least not optimally) in this context, showing that users are indeed facing issues. For example:
- Duplicating Word document using OpenXml and C#
- Word OpenXml Word Found Unreadable Content
- Open XML SDK: opening a Word template and saving to a different file-name
- docx document corrupted when copied though OpenXML C#
So, the questions are:
- What are the possible ways to correctly clone, or copy, those documents?
- Which way is the most efficient one?
The following sample class shows multiple ways to correctly copy pretty much any file and return the copy on a MemoryStream
or FileStream
from which you can then open a WordprocessingDocument
(Word), SpreadsheetDocument
(Excel), or PresentationDocument
(PowerPoint) and make whatever changes, using the Open XML SDK and optionally the Open-XML-PowerTools.
using System.IO;
namespace CodeSnippets.IO
{
/// <summary>
/// This class demonstrates multiple ways to clone files stored in the file system.
/// In all cases, the source file is stored in the file system. Where the return type
/// is a <see cref="MemoryStream"/>, the destination file will be stored only on that
/// <see cref="MemoryStream"/>. Where the return type is a <see cref="FileStream"/>,
/// the destination file will be stored in the file system and opened on that
/// <see cref="FileStream"/>.
/// </summary>
/// <remarks>
/// The contents of the <see cref="MemoryStream"/> instances returned by the sample
/// methods can be written to a file as follows:
///
/// var stream = ReadAllBytesToMemoryStream(sourcePath);
/// File.WriteAllBytes(destPath, stream.GetBuffer());
///
/// You can use <see cref="MemoryStream.GetBuffer"/> in cases where the MemoryStream
/// was created using <see cref="MemoryStream()"/> or <see cref="MemoryStream(int)"/>.
/// In other cases, you can use the <see cref="MemoryStream.ToArray"/> method, which
/// copies the internal buffer to a new byte array. Thus, GetBuffer() should be a tad
/// faster.
/// </remarks>
public static class FileCloner
{
public static MemoryStream ReadAllBytesToMemoryStream(string path)
{
byte[] buffer = File.ReadAllBytes(path);
var destStream = new MemoryStream(buffer.Length);
destStream.Write(buffer, 0, buffer.Length);
destStream.Seek(0, SeekOrigin.Begin);
return destStream;
}
public static MemoryStream CopyFileStreamToMemoryStream(string path)
{
using FileStream sourceStream = File.OpenRead(path);
var destStream = new MemoryStream((int) sourceStream.Length);
sourceStream.CopyTo(destStream);
destStream.Seek(0, SeekOrigin.Begin);
return destStream;
}
public static FileStream CopyFileStreamToFileStream(string sourcePath, string destPath)
{
using FileStream sourceStream = File.OpenRead(sourcePath);
FileStream destStream = File.Create(destPath);
sourceStream.CopyTo(destStream);
destStream.Seek(0, SeekOrigin.Begin);
return destStream;
}
public static FileStream CopyFileAndOpenFileStream(string sourcePath, string destPath)
{
File.Copy(sourcePath, destPath, true);
return new FileStream(destPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
}
}
On top of the above Open XML-agnostic methods, you can also use the following approach, e.g., in case you already have opened an OpenXmlPackage
such as a WordprocessingDocument
, SpreadsheetDocument
, or PresentationDocument
:
public void DoWorkCloningOpenXmlPackage()
{
using WordprocessingDocument sourceWordDocument = WordprocessingDocument.Open(SourcePath, false);
// There are multiple overloads of the Clone() method in the Open XML SDK.
// This one clones the source document to the given destination path and
// opens it in read-write mode.
using var wordDocument = (WordprocessingDocument) sourceWordDocument.Clone(DestPath, true);
ChangeWordprocessingDocument(wordDocument);
}
All of the above methods correctly clone, or copy, a document. But what is the most efficient one?
Enter our benchmark, which uses the BenchmarkDotNet
NuGet package:
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using BenchmarkDotNet.Attributes;
using CodeSnippets.IO;
using CodeSnippets.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace CodeSnippets.Benchmarks.IO
{
public class FileClonerBenchmark
{
#region Setup and Helpers
private const string SourcePath = "Source.docx";
private const string DestPath = "Destination.docx";
[Params(1, 10, 100, 1000)]
public static int ParagraphCount;
[GlobalSetup]
public void GlobalSetup()
{
CreateTestDocument(SourcePath);
CreateTestDocument(DestPath);
}
private static void CreateTestDocument(string path)
{
const string sentence = "The quick brown fox jumps over the lazy dog.";
string text = string.Join(" ", Enumerable.Range(0, 22).Select(i => sentence));
IEnumerable<string> texts = Enumerable.Range(0, ParagraphCount).Select(i => text);
using WordprocessingDocument unused = WordprocessingDocumentFactory.Create(path, texts);
}
private static void ChangeWordprocessingDocument(WordprocessingDocument wordDocument)
{
Body body = wordDocument.MainDocumentPart.Document.Body;
Text text = body.Descendants<Text>().First();
text.Text = DateTimeOffset.UtcNow.Ticks.ToString();
}
#endregion
#region Benchmarks
[Benchmark(Baseline = true)]
public void DoWorkUsingReadAllBytesToMemoryStream()
{
using MemoryStream destStream = FileCloner.ReadAllBytesToMemoryStream(SourcePath);
using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(destStream, true))
{
ChangeWordprocessingDocument(wordDocument);
}
File.WriteAllBytes(DestPath, destStream.GetBuffer());
}
[Benchmark]
public void DoWorkUsingCopyFileStreamToMemoryStream()
{
using MemoryStream destStream = FileCloner.CopyFileStreamToMemoryStream(SourcePath);
using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(destStream, true))
{
ChangeWordprocessingDocument(wordDocument);
}
File.WriteAllBytes(DestPath, destStream.GetBuffer());
}
[Benchmark]
public void DoWorkUsingCopyFileStreamToFileStream()
{
using FileStream destStream = FileCloner.CopyFileStreamToFileStream(SourcePath, DestPath);
using WordprocessingDocument wordDocument = WordprocessingDocument.Open(destStream, true);
ChangeWordprocessingDocument(wordDocument);
}
[Benchmark]
public void DoWorkUsingCopyFileAndOpenFileStream()
{
using FileStream destStream = FileCloner.CopyFileAndOpenFileStream(SourcePath, DestPath);
using WordprocessingDocument wordDocument = WordprocessingDocument.Open(destStream, true);
ChangeWordprocessingDocument(wordDocument);
}
[Benchmark]
public void DoWorkCloningOpenXmlPackage()
{
using WordprocessingDocument sourceWordDocument = WordprocessingDocument.Open(SourcePath, false);
using var wordDocument = (WordprocessingDocument) sourceWordDocument.Clone(DestPath, true);
ChangeWordprocessingDocument(wordDocument);
}
#endregion
}
}
The above benchmark is run as follows:
using BenchmarkDotNet.Running;
using CodeSnippets.Benchmarks.IO;
namespace CodeSnippets.Benchmarks
{
public static class Program
{
public static void Main()
{
BenchmarkRunner.Run<FileClonerBenchmark>();
}
}
}
And what are the results on my machine? Which method is the fastest?
BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores
.NET Core SDK=3.0.100
[Host] : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), X64 RyuJIT
DefaultJob : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), X64 RyuJIT
| Method | ParaCount | Mean | Error | StdDev | Median | Ratio |
| --------------------------------------- | --------- | --------: | --------: | --------: | --------: | ----: |
| DoWorkUsingReadAllBytesToMemoryStream | 1 | 1.548 ms | 0.0298 ms | 0.0279 ms | 1.540 ms | 1.00 |
| DoWorkUsingCopyFileStreamToMemoryStream | 1 | 1.561 ms | 0.0305 ms | 0.0271 ms | 1.556 ms | 1.01 |
| DoWorkUsingCopyFileStreamToFileStream | 1 | 2.394 ms | 0.0601 ms | 0.1100 ms | 2.354 ms | 1.55 |
| DoWorkUsingCopyFileAndOpenFileStream | 1 | 3.302 ms | 0.0657 ms | 0.0855 ms | 3.312 ms | 2.12 |
| DoWorkCloningOpenXmlPackage | 1 | 4.567 ms | 0.1218 ms | 0.3591 ms | 4.557 ms | 3.13 |
| | | | | | | |
| DoWorkUsingReadAllBytesToMemoryStream | 10 | 1.737 ms | 0.0337 ms | 0.0361 ms | 1.742 ms | 1.00 |
| DoWorkUsingCopyFileStreamToMemoryStream | 10 | 1.752 ms | 0.0347 ms | 0.0571 ms | 1.739 ms | 1.01 |
| DoWorkUsingCopyFileStreamToFileStream | 10 | 2.505 ms | 0.0390 ms | 0.0326 ms | 2.500 ms | 1.44 |
| DoWorkUsingCopyFileAndOpenFileStream | 10 | 3.532 ms | 0.0731 ms | 0.1860 ms | 3.455 ms | 2.05 |
| DoWorkCloningOpenXmlPackage | 10 | 4.446 ms | 0.0880 ms | 0.1470 ms | 4.424 ms | 2.56 |
| | | | | | | |
| DoWorkUsingReadAllBytesToMemoryStream | 100 | 2.847 ms | 0.0563 ms | 0.0553 ms | 2.857 ms | 1.00 |
| DoWorkUsingCopyFileStreamToMemoryStream | 100 | 2.865 ms | 0.0561 ms | 0.0786 ms | 2.868 ms | 1.02 |
| DoWorkUsingCopyFileStreamToFileStream | 100 | 3.550 ms | 0.0697 ms | 0.0881 ms | 3.570 ms | 1.25 |
| DoWorkUsingCopyFileAndOpenFileStream | 100 | 4.456 ms | 0.0877 ms | 0.0861 ms | 4.458 ms | 1.57 |
| DoWorkCloningOpenXmlPackage | 100 | 5.958 ms | 0.1242 ms | 0.2727 ms | 5.908 ms | 2.10 |
| | | | | | | |
| DoWorkUsingReadAllBytesToMemoryStream | 1000 | 12.378 ms | 0.2453 ms | 0.2519 ms | 12.442 ms | 1.00 |
| DoWorkUsingCopyFileStreamToMemoryStream | 1000 | 12.538 ms | 0.2070 ms | 0.1835 ms | 12.559 ms | 1.02 |
| DoWorkUsingCopyFileStreamToFileStream | 1000 | 12.919 ms | 0.2457 ms | 0.2298 ms | 12.939 ms | 1.05 |
| DoWorkUsingCopyFileAndOpenFileStream | 1000 | 13.728 ms | 0.2803 ms | 0.5196 ms | 13.652 ms | 1.11 |
| DoWorkCloningOpenXmlPackage | 1000 | 16.868 ms | 0.2174 ms | 0.1927 ms | 16.801 ms | 1.37 |
It turns out that DoWorkUsingReadAllBytesToMemoryStream()
is consistently the fastest method. However, the margin to DoWorkUsingCopyFileStreamToMemoryStream()
is easily with the margin of error. This means that you should open your Open XML documents on a MemoryStream
to do your processing whenever possible. And if you don't have to store the resulting document in your file system, this will even be much faster than unnecessarily using a FileStream
.
Wherever an output FileStream
is involved, you see a more "significant" difference (noting that a millisecond can make a difference if you process large numbers of documents). And you should note that using File.Copy()
is actually not such a good approach.
Finally, using the OpenXmlPackage.Clone()
method or one of its overrides turns out to be the slowest method. This is due to the fact that it involves more elaborate logic than just copying bytes. However, if all you got is a reference to an OpenXmlPackage
(or effectively one of its subclasses), the Clone()
method and its overrides are your best choice.
You can find the full source code in my CodeSnippets GitHub repository. Look at the CodeSnippets.Benchmark project and FileCloner class.
这篇关于克隆 Office Open XML 文档的最有效方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!