【问题标题】:Problems opening .xlsx file created with EPPlus and zipped in a folder with ICSharpCode.SharpZipLib打开使用 EPPlus 创建并使用 ICSharpCode.SharpZipLib 压缩到文件夹中的 .xlsx 文件时出现问题
【发布时间】:2014-05-05 12:24:22
【问题描述】:

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

Excel 无法打开文件 {Name}.xlsx,因为文件格式或文件扩展名无效。验证文件没有损坏并且文件扩展名与文件格式匹配

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();

至于文件名列表,我只是根据一些随意的东西生成一个名称,并在其末尾添加一个“.xlsx”扩展名。

我不知道我哪里出错了,有什么建议吗?

【问题讨论】:

    标签: c# asp.net xlsx epplus sharpziplib


    【解决方案1】:

    你必须先倒带内存流,然后才能读到东西(写操作后文件指针就是它的结尾):

    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);
    

    【讨论】:

    • 您先生,真是个天才。奇怪的是我还没有在任何示例中看到该代码,因为在发布到这里之前我一直在谷歌上搜索这个问题的废话。
    • @HansPetterNaumann 不幸的是我不是...我只是忘记了多次寻找流...
    • 嗯,那我希望下次能记住。不过,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-24
    • 1970-01-01
    • 2014-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多