2017-02-07 5 views
2

У меня есть следующая функция, которая возвращает FileStreamResult для моего приложения ASP.NET MVC.Создать ZipArchive файла Excel XLSX с EPPLUS C#

/// <summary> 
/// Generates a FileStreamResult containing a zip file with the EXCEL file in it 
/// </summary> 
/// <typeparam name="T">Type of object in the object list parameter</typeparam> 
/// <param name="objectList">The object list enumerable. This contains the data for the EXCEL file</param> 
/// <param name="fileName">The file name of the EXCEL</param> 
/// <returns>FileStreamResult</returns> 
public FileStreamResult CreateZipFileFileStreamResult<T>(IEnumerable<T> objectList, string fileName) 
{ 
    var ms = new MemoryStream(); 

    var contentType = System.Net.Mime.MediaTypeNames.Application.Zip; 

    ExcelPackage excelPackage = null; 

    ZipArchive archive = null; 

    try 
    { 
     excelPackage = new ExcelPackage(ms); 

     var workSheet1 = excelPackage.Workbook.Worksheets.Add("Sheet1"); 

     workSheet1.Cells["A1"].LoadFromCollection<T>(objectList, true); 

     excelPackage.SaveAs(ms); 



     ms.Seek(0, SeekOrigin.Begin); 

     archive = new ZipArchive(excelPackage.Stream, ZipArchiveMode.Create, true); 

     var newEntry = archive.CreateEntry(fileName, System.IO.Compression.CompressionLevel.Fastest); 

     var newEntryStream = newEntry.Open(); 

     var fsr = new FileStreamResult(excelPackage.Stream, contentType); 
     fsr.FileDownloadName = fileName + ".zip"; 

     return fsr; 
    } 
    catch (Exception ex) 
    { 
     if (archive != null) 
      archive.Dispose(); 

     if (excelPackage != null) 
      excelPackage.Dispose(); 

     if (ms != null) 
      ms.Dispose(); 

     throw; 
    } 
} 

Функция возвращает что-то, но находится в формате с разделенным XML, а не в одном файле XLSX.

Я хочу, чтобы он возвращал один ZIPPED-файл.

Это то, как выглядит текущий результат.

ZIP archive structure

Использовав помощь, оказанная @kuujinbo я создал эту функцию. Обратите внимание, что по какой-либо причине FileContentResult работает, и FileStreamResult не работает.

 /// <summary> 
     /// Generates a FileStreamResult containing a zip file with the EXCEL file in it 
     /// </summary> 
     /// <typeparam name="T">Type of object in the object list parameter</typeparam> 
     /// <param name="objectList">The object list enumerable. This contains the data for the EXCEL file</param> 
     /// <param name="fileName">The file name of the EXCEL</param> 
     /// <returns>FileStreamResult</returns>   
     public FileContentResult CreateZipFileFileContentResult<T>(IEnumerable<T> objectList, string fileName) 
     { 
      var contentType = System.Net.Mime.MediaTypeNames.Application.Zip; 

      using (var memoryStream = new System.IO.MemoryStream()) 
      { 
       using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) 
       { 
        using (var package = new OfficeOpenXml.ExcelPackage()) 
        { 
         var workSheet1 = package.Workbook.Worksheets.Add("Sheet1"); 
         workSheet1.Cells["A1"].LoadFromCollection<T>(objectList, true); 

         var firstRow = workSheet1.Row(1); 
         if (firstRow != null) 
          firstRow.Style.Font.Bold = true; 

         zip.AddEntry(fileName, package.GetAsByteArray()); 
         zip.Save(memoryStream); 
         var fcr = new FileContentResult(memoryStream.ToArray(), contentType); //NOTE: Using a File Stream Result will not work. 
         fcr.FileDownloadName = fileName + ".zip"; 
         return fcr; 
        } 
       } 
      } 
     } 
+0

выглядит вот что это должно быть. Файлы xlsx представляют собой затененные структуры opendocument. Я думаю, что ваш файловый проводник просто показывает содержимое ZIP прозрачно в иерархии каталогов (учитывая значок в левом верхнем углу). при переименовании .zip в .xlsx вы сможете открыть его с помощью Excel. – dlatikay

+1

+ вы никогда ничего не пишете в 'newEntryStream'? Кажется, что эта функция просто возвращает поток вывода EPPlus (который уже является внутренним ZIP и должен иметь расширение xlsx) с расширением .zip. – dlatikay

+0

Это сем, вы правы. Я посмотрю. –

ответ

3

Поскольку EPPlus внутренне использует версию DotNetZip (посмотрите на исходный код) попытаться сделать то же самое. ИМХО их дизайнерское решение много говорит о том, почему некоторые выбирают не для использования ZipArchive.

class TestObject 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

IEnumerable<TestObject> objectList = new List<TestObject>() 
{ 
    { new TestObject() {Id = 0, Name = "zero" } }, 
    { new TestObject() {Id = 1, Name = "one" } } 
}; 
string ExcelName = "test.xlsx"; 
string ZipName = "test.zip"; 

public ActionResult DotnetZip() 
{ 
    using (var stream = new MemoryStream()) 
    { 
     using (ZipFile zip = new ZipFile()) 
     { 
      using (var package = new ExcelPackage()) 
      { 
       var sheet = package.Workbook.Worksheets.Add("Sheet1"); 
       sheet.Cells["A1"].LoadFromCollection<TestObject>(objectList, true); 
       zip.AddEntry(ExcelName, package.GetAsByteArray()); 
       zip.Save(stream); 
       return File(
        stream.ToArray(), 
        System.Net.Mime.MediaTypeNames.Application.Zip, 
        ZipName 
       ); 
      } 
     } 
    } 
} 

испытаны и работа:

enter image description here

+0

Здравствуйте, я пытаюсь получить ZIP-файл, а не EXCEL fille. Я уже знаю, как получить файл EXCEL. :) –

+1

@DragosDurlut - извините, мой плохой. Обновлен ответ рабочим решением. – kuujinbo

+0

они используют модифицированное (более быстрое) сжатие? или как мог бы второй проход получить еще ~ 20% упаковки? – dlatikay

Смежные вопросы