将MemoryStream写入响应对象

43

我正在使用以下代码来流式传输存储在MemoryStream对象中的pptx文件,但是当我打开它时,PowerPoint会显示“修复”消息,请问将MemoryStream正确写入Response对象的方法是什么?

HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.AppendHeader("Content-Type", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}.pptx;", getLegalFileName(CurrentPresentation.Presentation_NM)));                
response.BinaryWrite(masterPresentation.ToArray());
response.End();

不要忘记清空输出流。 - Nudier Mena
@Nudier 有代码示例吗?我在 BinaryWrite 后执行了 response.Flush(),但仍然出现相同的错误消息。 - Ali
你能展示一下创建MemoryStream的代码吗? - Hans
8个回答

76

我遇到了同样的问题,唯一有效的解决方案是:

Response.Clear();
Response.ContentType = "Application/msword";
Response.AddHeader("Content-Disposition", "attachment; filename=myfile.docx");
Response.BinaryWrite(myMemoryStream.ToArray());
// myMemoryStream.WriteTo(Response.OutputStream); //works too
Response.Flush();
Response.Close();
Response.End();

3
根据这篇文章Response.End()会抛出异常,这不是你想要的结果。使用HttpContext.Current.ApplicationInstance.CompleteRequest(); - jimboweb

16

假设您可以获得一个 Stream、FileStream 或 MemoryStream,您可以这样做:

Stream file = [Some Code that Gets you a stream];
var filename = [The name of the file you want to user to download/see];

if (file != null && file.CanRead)
{
    context.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
    context.Response.ContentType = "application/octet-stream";
    context.Response.ClearContent();
    file.CopyTo(context.Response.OutputStream);
}

这是我工作代码的复制粘贴,所以内容类型可能不是你要找的,但在最后一行将流写入响应是关键。


7

不要在MemoryStream中创建PowerPoint演示文稿,而是直接将其写入Response.OutputStream。这样,您就不需要在服务器上浪费任何内存,因为组件将直接将输出流传输到网络套接字流中。所以,不要将MemoryStream传递给生成此演示文稿的函数,而是直接传递Response.OutputStream。


你确定这个实现能够生成有效的PowerPoint文件吗?如果你将这个MemoryStream写入服务器上的一个文件,然后尝试打开它,会发生什么:File.WriteAllBytes(@"c:\test.pptx", masterPresentation.ToArray())。你能成功打开这个文件吗?此外,你应该修复控件的实现,使其使用Stream而不是MemoryStream,特别是在像ASP.NET这样的服务器端应用程序中,MemoryStream效率极低。 - Darin Dimitrov
1
你怎么知道这是一个有效的文件?你还没有将它存储到文件中。 - Darin Dimitrov
实际上问题出现在演示文稿超过30张幻灯片时,由于我们流式传输的方式会影响文件大小,这是我最好的猜测。 - Ali
@Ali,除非你设置了Response.BufferOutput = false,否则在写入Response缓冲区后需要执行Response.flush()。然后使用打开的MemoryStream对象,stream.WriteTo(Response.OutputStream)可以正常工作。 - Dan Randolph
此外,如果您的MemoryStream对象没有在“Using(...)”语句中创建,请确保在WriteTo调用之后执行stream.Close()。 - Dan Randolph
显示剩余2条评论

4

首先,我们需要写入内存流,然后利用内存流方法"WriteTo"可以像下面的代码一样将其写入页面响应。

   MemoryStream filecontent = null;
   filecontent =//CommonUtility.ExportToPdf(inputXMLtoXSLT);(This will be your MemeoryStream Content)
   Response.ContentType = "image/pdf";
   string headerValue = string.Format("attachment; filename={0}", formName.ToUpper() + ".pdf");
   Response.AppendHeader("Content-Disposition", headerValue);

   filecontent.WriteTo(Response.OutputStream);

   Response.End();

FormName是给定的文件名,此代码将通过调用弹出窗口使生成的PDF文件可下载。


4

尝试使用这个

Response.Clear();
Response.AppendHeader("Content-Type", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
Response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}.pptx;", getLegalFileName(CurrentPresentation.Presentation_NM)));
Response.Flush();                
Response.BinaryWrite(masterPresentation.ToArray());
Response.End();

3
我的问题是在下载之前,我的流没有设置为原点。
Response.Clear();
Response.ContentType = "Application/msword";
Response.AddHeader("Content-Disposition", "attachment; filename=myfile.docx");

//ADDED THIS LINE
myMemoryStream.Seek(0,SeekOrigin.Begin);

myMemoryStream.WriteTo(Response.OutputStream); 
Response.Flush();
Response.Close();

太棒了!这就是真正的解决方案! - MgSam

1
我尝试了所有的end、close、flush和System.Web.HttpContext.Current.ApplicationInstance.CompleteRequest()变体,但都没有起作用。
然后我将内容长度添加到头部: Response.AddHeader("Content-Length", asset.File_Size.ToString());
在这个例子中,asset是一个有一个Int32叫做File_Size的类。
这对我起了作用,其他方法都没有。

0
我遇到了同样的问题。 尝试这个:复制到MemoryStream -> 删除文件 -> 下载。
string absolutePath = "~/your path";
try {
    //copy to MemoryStream
    MemoryStream ms = new MemoryStream();
    using (FileStream fs = File.OpenRead(Server.MapPath(absolutePath))) 
    { 
        fs.CopyTo(ms); 
    }

    //Delete file
    if(File.Exists(Server.MapPath(absolutePath)))
       File.Delete(Server.MapPath(absolutePath))

    //Download file
    Response.Clear()
    Response.ContentType = "image/jpg";
    Response.AddHeader("Content-Disposition", "attachment;filename=\"" + absolutePath + "\"");
    Response.BinaryWrite(ms.ToArray())
}
catch {}

Response.End();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接