c#-打开用EPPlus创建并用ICSharpCode.SharpZipLib压缩在文件夹中的.xlsx文件时出现问题

我正在使用EPPlus创建ExcelPackages(xlsx文档)列表,并将它们作为ZipEntries添加到ZipOutputStream.我认为Excel文档应该是有效的,因为当我将其中一个文档写入Response对象而无需压缩时,我可以很好地打开它们.
zip文件夹已按预期创建,并且文件在那里并且似乎没有空,但是当我尝试打开它们时,在Excel中出现以下错误:

Excel cannot open the file {Name}.xlsx because the file format or file extension is not valid. Verify that file has not been corrupted and that the file extension matches the format of the file

List<ExcelPackage> documents = new List<ExcelPackage>();
List<string> fileNames = new List<string>();

//Code for fetching documents and filenames here (removed for the sake of readability)

Response.Clear();
Context.Response.BufferOutput = false; 
Response.ContentType = "application/zip";
Response.AppendHeader("content-disposition", "attachment; filename=\"random-foldername.zip\"");
Response.CacheControl = "Private";
Response.Cache.SetExpires(DateTime.Now.AddMinutes(3)); 

ZipOutputStream zipOutputStream = new ZipOutputStream(Response.OutputStream);
zipOutputStream.SetLevel(3); //0-9, 9 being the highest level of compression
byte[] buffer = null;

for (int i = 0; i < documents.Count; i++)
{
    MemoryStream ms = new MemoryStream();

    documents[i].SaveAs(ms);

    ZipEntry entry = new ZipEntry(ZipEntry.CleanName(fileNames[i]));

    zipOutputStream.PutNextEntry(entry);
    buffer = new byte[ms.Length];

    ms.Read(buffer, 0, buffer.Length);
    entry.Size = ms.Length;

    ms.Close();

    zipOutputStream.Write(buffer, 0, buffer.Length);
    zipOutputStream.CloseEntry();

}
zipOutputStream.Finish();
zipOutputStream.Close();

Response.End();

至于文件名列表,im只是基于任意东西生成一个名称,并在其末尾添加一个“ .xlsx”扩展名.

我不确定我在哪里错了,有什么建议吗?

解决方法:

您必须先倒带内存流,然后才能读取某些内容(写操作文件指针位于其末尾之后):

ms.Seek(0, SeekOrigin.Begin)
ms.Read(buffer, 0, buffer.Length);

也就是说,MemoryStream只是一个字节数组,因此您甚至不需要分配和读取一个新的代码,然后再编写以下代码:

buffer = new byte[ms.Length];

ms.Read(buffer, 0, buffer.Length);
entry.Size = ms.Length;

ms.Close();

zipOutputStream.Write(buffer, 0, buffer.Length);

可以简单地替换为:

entry.Size = ms.Length;
zipOutputStream.Write(ms.GetBuffer(), 0, ms.Length);
ms.Close();

最后说明:如果您不想使用内部MemoryStream缓冲区(出于任何原因)而想要它的修剪后的副本(就像您手动进行的那样),则只需使用ToArray()方法,如下所示:

var buffer = ms.ToArray();
ms.Close();
entry.Size = buffer.Length;
zipOutputStream.Write(buffer, 0, buffer.Length);
上一篇:【DB笔试面试826】在Oracle中,ASH和AWR的关系是什么?


下一篇:空间索引 - GeoHash算法及其实现优化