Проблемы с открытием.xlsx файла, созданного с помощью EPPlus и заархивированного в папку с ICSharpCode.SharpZipLib

Я создаю список ExcelPackages (документы xlsx), используя EPPlus, и добавляю их в ZipOutputStream как ZipEntries. Я думаю, что документы Excel должны быть действительными, так как я могу открыть их очень хорошо, когда я записываю один из них в объект Response без архивирования.
Папка zip создается, как и ожидалось, и файлы там есть, и они не кажутся пустыми, но при попытке открыть их я получаю следующую ошибку в Excel:

Excel не может открыть файл {Имя}.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" в конец.

Я не уверен, где я здесь не так, какие-либо предложения?

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);
Другие вопросы по тегам