2014-01-21 87 views
3

我从OpenXML的MemoryStream出现问题。我成功地打开了一个Word文件,通过HttpResponse进行更改并下载它,如果我使用单一方法完成所有步骤的话。C#从OpenXML返回内存流导致损坏的Word文件

但是,如果我试图通过返回MemoryStream在两个不同的类(或方法)中做到这一点,我得到一个损坏的word文件。我想过冲洗或缓冲区问题,但我找不到解决方案。

这里是工作代码:

public void FillTemplateOpenXmlWord(HttpResponse response) 
    { 
     string filePath = @"c:\template.docx"; 
     byte[] filebytes = File.ReadAllBytes(filePath); 

     using (MemoryStream stream = new MemoryStream(filebytes)) 
     { 
      using (WordprocessingDocument myDoc = WordprocessingDocument.Open(stream, true)) 
      { 
       // do some changes 
       ... 
       myDoc.MainDocumentPart.Document.Save(); 
      } 

      string docx = "docx"; 
      response.Clear(); 
      response.ClearHeaders(); 
      response.ClearContent(); 
      response.AddHeader("content-disposition", "attachment; filename=\"" + docx + ".docx\""); 
      response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; 
      response.ContentEncoding = Encoding.GetEncoding("ISO-8859-1"); 
      stream.Position = 0; 
      stream.CopyTo(response.OutputStream); 
      response.End(); 
     } 
    } 

这里的非工作代码:

public void OpenFile(HttpResponse response) 
    { 
     MemoryStream stream = this.FillTemplateOpenXmlWord(); 

     string docx = "docx"; 
     response.Clear(); 
     response.ClearHeaders(); 
     response.ClearContent(); 
     response.AddHeader("content-disposition", "attachment; filename=\"" + docx + ".docx\""); 
     response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; 
     response.ContentEncoding = Encoding.GetEncoding("ISO-8859-1"); 
     stream.Position = 0; 
     stream.CopyTo(response.OutputStream); 
     response.End(); 
    } 

    public MemoryStream FillTemplateOpenXmlWord() 
    { 
     string filePath = @"c:\template.docx"; 
     byte[] filebytes = File.ReadAllBytes(filePath); 

     using (MemoryStream stream = new MemoryStream(filebytes)) 
     { 
      using (WordprocessingDocument myDoc = WordprocessingDocument.Open(stream, true)) 
      { 
       // do some changes 
       ... 
       myDoc.MainDocumentPart.Document.Save(); 
      } 

      return stream; 
     } 
    } 

任何想法?

谢谢

回答

1

看起来像流正在关闭,当你返回。它在一个使用块中。一旦filltemplate程序结束就不会关闭内存流?

+0

我刚刚发现了同样的事情。当我得到答案时,我非常接近编辑我的问题并给出解决方案。 你说得对!我在使用条款中返回一个流。退货不会创建副本,而是创建参考。所以,在调用方法中,我得到了一个不在using子句中的流的引用。该流被丢弃,内容不再可用。 谢谢 – DotNetBeliever

0

gashac发布的答案没有描述通过不在流上调用dispose将会遇到的问题。

不处理存储器流导致内存泄漏(与“使用条款”相同)。

内存流将数据保存在内存中,而文件流将数据保留在硬盘上。

解决方案:

保存存储器流入一个字节数组,配置内存流并返回字节组。

如何返回字节组,而不是流

请参见下面的线程返回一个文件作为字节组: HttpResponseMessage Content won't display PDF

2

下面是我使用的是什么,从内存流产生的OpenXML文件。在这种情况下,它会根据服务器上的模板生成XLSX文件,但它应该与其他OpenXml格式类似。

控制器动作:

public class ExportController : Controller 
{ 
    public FileResult Project(int id) 
    { 
     var model = SomeDateModel.Load(id); 
     ProjectExport export = new ProjectExport(); 
     var excelBytes = export.Export(model); 
     FileResult fr = new FileContentResult(excelBytes, "application/vnd.ms-excel") 
     { 
      FileDownloadName = string.Format("Export_{0}_{1}.xlsx", DateTime.Now.ToString("yyMMdd"), model.Name) 
     }; 

     return fr; 
    } 
} 

// Helper类

public class ProjectExport 
{ 
    private WorkbookPart workbook; 
    private Worksheet ws; 

    public byte[] Export(SomeDateModel model) 
    { 
     var template = new FileInfo(HostingEnvironment.MapPath(@"~\Export\myTemplate.xlsx")); 
     byte[] templateBytes = File.ReadAllBytes(template.FullName); 

     using (var templateStream = new MemoryStream()) 
     { 
      templateStream.Write(templateBytes, 0, templateBytes.Length); 
      using (var excelDoc = SpreadsheetDocument.Open(templateStream, true)) 
      { 
       workbook = excelDoc.WorkbookPart; 
       var sheet = workbook.Workbook.Descendants<Sheet>().First(); 

       ws = ((WorksheetPart)workbook.GetPartById(sheet.Id)).Worksheet; 

       sheet.Name = model.Name; 
       // Here write some other stuff for setting values in cells etc... 
      } 
      templateStream.Position = 0; 
      var result = templateStream.ToArray(); 
      templateStream.Flush(); 

      return result; 
     } 
    }