当前位置: 首页 > 编程语言 > C#

MVC3返回多个pdf作为zip文件共享

时间:2023-04-10 22:37:08 C#

这样每个页面都是一个单独的pdf(具有自己唯一的标题)并返回一个zip文件。我的原始代码如下所示:publicFileStreamResultDownloadPDF(){MemoryStreamworkStream=newMemoryStream();文件文件=新文件();PdfWriter.GetInstance(文档,workStream).CloseStream=false;文档.Open();//填充pdf项目document.Close();byte[]byteInfo=workStream.ToArray();workStream.Write(byteInfo,0,byteInfo.Length);workStream.Position=0;FileStreamResultfileResult=newFileStreamResult(workStream,"应用程序/pdf");fileResult.FileDownloadName="文件名";返回文件结果;用gzip压缩文件看起来很简单,但我不知道如何gzip多个文件并将它们作为一个zip文件返回。或者我应该使用gzip以外的东西,比如dotnetzip或sharpzip?提前致谢!如果您的解决方案有效,最简单的方法就是保持原样。另一方面,我对您对DoTNetZip库的使用有一些评论。首先,您的代码有点误导。在这部分:byte[]byteInfo=workStream.ToArray();zip.Save(workStream);workStream.Write(byteInfo,0,byteInfo.Length);workStream.Position=0;...您正在将workStream读入数组。但是,您还没有向workStream写入任何内容,因此该数组为空且长度为零。然后将zip保存到工作流程中。然后将数组(长度为零)写入相同的工作流程。这是一个NO-OP。最后你重置位置。您可以将所有内容替换为:zip.Save(workStream);workStream.Position=0;这不是DotNetZip本身的问题,这只是您对流操作方式的误解。好的,接下来,您将不必要地分配临时缓冲区(内存流)。将MemoryStream视为一个字节数组,上面有一个Stream包装器以支持Write()、Read()、Seek()等。基本上,您的代码是将数据写入临时缓冲区,然后告诉DotNetZip从中读取数据临时缓冲区到它自己的缓冲区进行压缩。您不需要那个临时缓冲区。它的工作方式与您完成的方式相同,但效率更高。DotNetZip有一个接受编写器委托的AddEntry()重载。委托是DotNetZip调用的一个函数,它告诉您的应用程序将项目的内容写入zip存档。您的代码写入未压缩的字节,DotNetZip压缩并将它们写入输出流。在该编写器委托中,您的代码直接写入DotNetZip流-DotNetZip传递给委托的流。没有中间缓冲区。高效率。请记住,关闭包裹是有规则的。如果在for循环中调用此编写器委托,则需要有一种方法来检索与委托中的zipentry对应的“bla”。在调用zip.Save()之前,委托不会被执行!所以你不能依赖循环中'bla'的值。publicFileStreamResultDownloadPDF(){MemoryStreamworkStream=newMemoryStream();using(varzip=newZipFile()){foreach(BlablainBlas){zip.AddEntry(bla.filename+".pdf",(name,stream)=>{varthisBla=GetBlaFromName(name);文档文档=newDocument();PdfWriter.GetInstance(document,stream).CloseStream=false;document.Open();//将thisBla的PDF内容写入流/PdfWriterdocument.Close();});}zip.Save(workStream);}workStream.Position=0;FileStreamResultfileResult=newFileStreamResult(workStream,System.Net.Mime.MediaTypeNames.Application.Zip);fileResult.FileDownloadName="MultiplePDFs.zip";返回文件结果;最后,我不是特别喜欢从MemoryStream创建FileStreamResult。问题是您的整个zip文件都保存在内存中,这对内存使用来说非常困难。如果您的zip文件很大,您的代码会将所有内容保存在内存中。我对MVC3模型的了解还不够,无法知道其中是否有任何可以帮助解决这个问题的东西。如果没有,您可以使用匿名管道来反转流的方向并消除将所有压缩数据保留在内存中的需要。这就是我的意思:创建FileStreamResult需要您提供可读流。如果您使用MemoryStream,为了使其可读,您需要先写入它,然后返回位置0,然后再将其传递给FileStreamResult构造函数。这意味着该zip文件的所有内容必须在某个时间点连续保存在内存中。假设您可以为FileStreamResult构造函数提供可读流,这将允许读取器在您写入时准确读取。这就是匿名管道流所做的。它允许您的代码使用可写流,而MVC代码获取其可读流。这是它在代码中的样子。staticStreamGetPipedStream(ActionwriteAction){AnonymousPipeServerStreampipeServer=newAnonymousPipeServerStream();ThreadPool.QueueUserWorkItem(s=>{使用(pipeServer){writeAction(pipeServer);pipeServer.WaitForPipeDrain();}});返回新的AnonymousPipeClientStream(pipeServer.GetClientHandleAsString());}publicFileStreamResultDownloadPDF(){varreadable=GetPipedStream(output=>{using(varzip=newZipFile()){foreach(BlablainBlas){zip.AddEntry(bla.filename+".pdf",(name,stream)=>{varthisBla=GetBlaFromName(name);Documentdocument=newDocument();PdfWriter.GetInstance(document,stream).CloseStream=false;document.Open();//将thisBla的PDF内容写入PdfWriter文档.Close();});}zip.Save(输出);}});varfileResult=newFileStreamResult(可读,System.Net.Mime.MediaTypeNames.Application.Zip);fileResult.FileDownloadName="MultiplePDFs.zip";返回文件结果;我没有尝试过这个,但它应该工作。这具有比您编写的内容更有效的内存优势。缺点是使用命名管道和几个匿名函数相当复杂。仅当zip内容超出>1MB范围时才有意义。如果你的拉链比那个小,那么你可以按照我上面展示的第一种方式来做。附录为什么不能在匿名方法中依赖bla的值?有两个关键点。首先,foreach循环定义了一个名为bla的变量,它在每次循环时取不同的值。似乎很明显,但值得明确说明。其次,匿名方法作为参数传递给ZipFile.AddEntry()方法,它不会在foreach循环运行时运行。事实上,在ZipFile.Save()上,匿名方法会为每个添加的条目重复调用一次。如果您在匿名方法中引用bla,它会获得分配给bla的最后一个值,因为这是ZipFile.Save()运行时bla持有的值。这就是导致延迟执行困难的原因。你想要的是来自foreach循环的每个不同的bla值,在调用匿名函数时可以访问-稍后,在foreach循环之外。您可以使用如上所示的实用程序方法(GetBlaForName())来执行此操作。你也可以用一个额外的闭包来做到这一点,像这样:=false;document.Open();//将bla的PDF内容写入PdfWriterdocument.Close();};}foreach(varblainBlas){zip.AddEntry(bla.filename+".pdf",GetEntryWriter(bla));}GetEntryWriter返回一个方法——实际上是一个Action,它只是一个类型化的方法。每次循环,都会创建该Action的一个新实例,并为bla引用不同的值。直到ZipFile.Save()调用那个行动。我最终使用DotNetZip而不是SharpZipLib,因为解决方案更简单。这就是我最终所做的并且工作正常,但如果有人有任何建议/更改,我会很高兴。publicFileStreamResultDownloadPDF(){MemoryStreamworkStream=newMemoryStream();ZipFilezip=newZipFile();foreach(BlablainBlas){MemoryStreampdfStream=newMemoryStream();文件文件=新文件();PdfWriter.GetInstance(文档,pdfStream).CloseStream=false;文档.Open();//PDF内容document.Close();byte[]pdfByteInfo=pdfStream.ToArray();zip.AddEntry(bla.filename+".pdf",pdfByteInfo);pdfStream.Close();}zip.Save(workStream);workStream.Position=0;FileStreamResultfileResult=newFileStreamResult(workStream,System.Net.Mime.MediaTypeNames.Application.Zip);fileResult.FileDownloadName="MultiplePDFs.zip";返回文件结果;正如Turnkey所说-SharpZipLib非常适合处理多个文件和内存流。只需预览需要压缩的文件并将它们添加到存档中即可。这是一个例子://保存到内存MemoryStreamms=newMemoryStream();ZipOutputStreamzipStream=newZipOutputStream(ms);//使用它来检查ZIP:)//FileStreamfileOut=File.OpenWrite(@"c:\test1.zip");//ZipOutputStreamzipStream=newZipOutputStream(fileOut);zipStream.SetLevel(0);//循环你的页面(文件)foreach(stringfilenameinfiles){//在归档文件中创建和命名条目FileInfofi=newFileInfo(filename);ZipEntryzipEntry=newZipEntry(fi.Name);zipStream.PutNextEntry(zipEntry);//将条目放入存档(从文件或数据库)ReadFileToZip(zipStream,filename);zipStream.CloseEntry();}//从内存复制到文件或将输出发送到浏览器,就像您所做的那样zipStream.Close();我不知道你是如何得到压缩的信息的,所以我认为该文件是好的:)//////读取文件并将其放入ZIP流///privatevoidReadFileToZip(ZipOutputStreamzipStream,stringfilename){//简单的文件读取:)using(FileStreamfs=File.OpenRead(filename)){StreamUtils.Copy(fs,zipStream,新字节[4096]);我推荐使用SharpZipLib压缩成一个标准的zip文件将文件放入一个临时文件夹并使用FastZip类来制作zip。以上是C#学习教程:MVC3返回多个pdf为zip文件分享全部内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: