如何将 OpenXML 从模板创建的 Word 文档转换为 MemoryStream?
How to convert Word document created from template by OpenXML into MemoryStream?
我需要在 ASP.NET 控制器方法中 return 记录为 MemoryStream 以在网页上下载它。我不想把这个文件保存在文件上,然后读取为MemoryStream和return。
注意:重载方法 WordprocessingDocument.CreateFromTemplate(template) 没有流选项 vs WordprocessingDocument.Create(stream, ...)
保存临时文件的解决方案如下。
public static MemoryStream GetWordDocumentFromTemplate()
{
string tempFileName = Path.GetTempFileName();
var templatePath = AppDomain.CurrentDomain.BaseDirectory + @"Controllers\" + templateFileName;
using (var document = WordprocessingDocument.CreateFromTemplate(templatePath))
{
var body = document.MainDocumentPart.Document.Body;
//add some text
Paragraph paraHeader = body.AppendChild(new Paragraph());
Run run = paraHeader.AppendChild(new Run());
run.AppendChild(new Text("This is body text"));
OpenXmlPackage savedDoc = document.SaveAs(tempFileName); // Save result document, not modifying the template
savedDoc.Close(); // can't read if it's open
document.Close();
}
var memoryStream = new MemoryStream(File.ReadAllBytes(tempFileName)); // this works but I want to avoid saving and reading file
//memoryStream.Position = 0; // should I rewind it?
return memoryStream;
}
不幸的是,这似乎不可能;如果您转到 "SaveAs" 上的定义并尽可能向下钻取,您将得到:
protected abstract OpenXmlPackage OpenClone(string path, bool isEditable, OpenSettings openSettings);
所以看起来原始字符串 XML 是在运行时构造并在内部保存到文件中,并且没有只生成原始字符串(或流)的方法。
找到了无需保存到中间临时文件即可工作的答案。技巧是打开模板进行编辑,使用可访问流,将文档类型从模板更改为文档,然后 return 这个流。
public static MemoryStream GetWordDocumentStreamFromTemplate()
{
var templatePath = AppDomain.CurrentDomain.BaseDirectory + "Controllers\" + templateFileName;
var memoryStream = new MemoryStream();
using (var fileStream = new FileStream(templatePath, FileMode.Open, FileAccess.Read))
fileStream.CopyTo(memoryStream);
using (var document = WordprocessingDocument.Open(memoryStream, true))
{
document.ChangeDocumentType(WordprocessingDocumentType.Document); // change from template to document
var body = document.MainDocumentPart.Document.Body;
//add some text
Paragraph paraHeader = body.AppendChild(new Paragraph());
Run run = paraHeader.AppendChild(new Run());
run.AppendChild(new Text("This is body text"));
document.Close();
}
memoryStream.Position = 0; //let's rewind it
return memoryStream;
}
完整测试方案:
https://github.com/sergeklokov/WordDocumentByOpenXML/blob/master/WordDocumentByOpenXML/Program.cs
我需要在 ASP.NET 控制器方法中 return 记录为 MemoryStream 以在网页上下载它。我不想把这个文件保存在文件上,然后读取为MemoryStream和return。 注意:重载方法 WordprocessingDocument.CreateFromTemplate(template) 没有流选项 vs WordprocessingDocument.Create(stream, ...)
保存临时文件的解决方案如下。
public static MemoryStream GetWordDocumentFromTemplate()
{
string tempFileName = Path.GetTempFileName();
var templatePath = AppDomain.CurrentDomain.BaseDirectory + @"Controllers\" + templateFileName;
using (var document = WordprocessingDocument.CreateFromTemplate(templatePath))
{
var body = document.MainDocumentPart.Document.Body;
//add some text
Paragraph paraHeader = body.AppendChild(new Paragraph());
Run run = paraHeader.AppendChild(new Run());
run.AppendChild(new Text("This is body text"));
OpenXmlPackage savedDoc = document.SaveAs(tempFileName); // Save result document, not modifying the template
savedDoc.Close(); // can't read if it's open
document.Close();
}
var memoryStream = new MemoryStream(File.ReadAllBytes(tempFileName)); // this works but I want to avoid saving and reading file
//memoryStream.Position = 0; // should I rewind it?
return memoryStream;
}
不幸的是,这似乎不可能;如果您转到 "SaveAs" 上的定义并尽可能向下钻取,您将得到:
protected abstract OpenXmlPackage OpenClone(string path, bool isEditable, OpenSettings openSettings);
所以看起来原始字符串 XML 是在运行时构造并在内部保存到文件中,并且没有只生成原始字符串(或流)的方法。
找到了无需保存到中间临时文件即可工作的答案。技巧是打开模板进行编辑,使用可访问流,将文档类型从模板更改为文档,然后 return 这个流。
public static MemoryStream GetWordDocumentStreamFromTemplate()
{
var templatePath = AppDomain.CurrentDomain.BaseDirectory + "Controllers\" + templateFileName;
var memoryStream = new MemoryStream();
using (var fileStream = new FileStream(templatePath, FileMode.Open, FileAccess.Read))
fileStream.CopyTo(memoryStream);
using (var document = WordprocessingDocument.Open(memoryStream, true))
{
document.ChangeDocumentType(WordprocessingDocumentType.Document); // change from template to document
var body = document.MainDocumentPart.Document.Body;
//add some text
Paragraph paraHeader = body.AppendChild(new Paragraph());
Run run = paraHeader.AppendChild(new Run());
run.AppendChild(new Text("This is body text"));
document.Close();
}
memoryStream.Position = 0; //let's rewind it
return memoryStream;
}
完整测试方案: https://github.com/sergeklokov/WordDocumentByOpenXML/blob/master/WordDocumentByOpenXML/Program.cs