2016-10-21 4 views
6

Я пытаюсь создать zip-файл, содержащий один или несколько файлов.
Я использую .NET framework 4.5 и, более конкретно, пространство имен System.IO.Compression.
Цель состоит в том, чтобы позволить пользователю загружать zip-файл через приложение ASP.NET MVC.
Почтовый файл генерируется и отправляется клиенту, но когда я пытаюсь его открыть, сделав двойной щелчок на нем, я получаю следующую ошибку:
Windows не может открыть папку. Сжатая (сжатая) папка ... недействительна.
Вот мой код:Недопустимый почтовый файл после его создания с помощью System.IO.Compression

[HttpGet] 
public FileResult Download() 
{ 
    var fileOne = CreateFile(VegieType.POTATO); 
    var fileTwo = CreateFile(VegieType.ONION); 
    var fileThree = CreateFile(VegieType.CARROT); 

    IEnumerable<FileContentResult> files = new List<FileContentResult>() { fileOne, fileTwo, fileThree }; 
    var zip = CreateZip(files); 

    return zip; 
} 

private FileContentResult CreateFile(VegieType vType) 
{ 
    string fileName = string.Empty; 
    string fileContent = string.Empty; 

    switch (vType) 
    { 
     case VegieType.BATATA: 
      fileName = "batata.csv"; 
      fileContent = "THIS,IS,A,POTATO"; 
      break; 
     case VegieType.CEBOLA: 
      fileName = "cebola.csv"; 
      fileContent = "THIS,IS,AN,ONION"; 
      break; 
     case VegieType.CENOURA: 
      fileName = "cenoura.csv"; 
      fileContent = "THIS,IS,A,CARROT"; 
      break; 
     default: 
      break; 
    } 

    var fileBytes = Encoding.GetEncoding(1252).GetBytes(fileContent); 
    return File(fileBytes, MediaTypeNames.Application.Octet, fileName); 
} 

private FileResult CreateZip(IEnumerable<FileContentResult> files) 
{ 
    byte[] retVal = null; 

    if (files.Any()) 
    { 
     using (MemoryStream zipStream = new MemoryStream()) 
     { 
      using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create, false)) 
      { 
       foreach (var f in files) 
       { 
        var entry = archive.CreateEntry(f.FileDownloadName, CompressionLevel.Fastest); 
        using (var entryStream = entry.Open()) 
        { 
         entryStream.Write(f.FileContents, 0, f.FileContents.Length); 
         entryStream.Close(); 
        } 
       } 

       zipStream.Position = 0; 
       retVal = zipStream.ToArray(); 
      } 
     } 
    } 

    return File(retVal, MediaTypeNames.Application.Zip, "horta.zip"); 
} 

Может кто-нибудь, пожалуйста, пролить некоторый свет на то, почему окна говорят, что мой почтовый недопустимый файл, когда я дважды щелкните на нем.
Окончательное рассмотрение, я могу открыть его с помощью 7-Zip.

ответ

8

Вам нужно получить буфер MemoryStream через ToArray после того, как объект ZipArchive будет удален. В противном случае вы получите поврежденный архив.

Обратите внимание, что я изменил параметры конструктора ZipArchive, чтобы сохранить его при добавлении записей.

Существует ряд контрольных сумм, когда ZipArchive находится на расстоянии, поэтому, если вы читаете MemoryStream раньше, он все еще не завершен.

private FileResult CreateZip(IEnumerable<FileContentResult> files) 
    { 
     byte[] retVal = null; 

     if (files.Any()) 
     { 
      using (MemoryStream zipStream = new MemoryStream()) 
      { 
       using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true)) 
       { 
        foreach (var f in files) 
        { 
         var entry = archive.CreateEntry(f.FileDownloadName, CompressionLevel.Fastest); 
         using (BinaryWriter writer = new BinaryWriter(entry.Open())) 
         {         
          writer.Write(f.FileContents, 0, f.FileContents.Length); 
          writer.Close(); 
         } 
        } 

        zipStream.Position = 0; 
       } 
       retVal = zipStream.ToArray(); 
      } 
     } 

     return File(retVal, MediaTypeNames.Application.Zip, "horta.zip"); 
    } 
+0

OP сказал, что он может открыть его с помощью 7-Zip. Так что Dispose не должен быть проблемой – GauravKP

+0

Я тестировал как его версию метода, так и не открывал с помощью zip-файла Windows, с помощью моего метода, вы можете открыть с помощью zip-файла Windows, вы его протестировали? –

+0

Подумайте о настройке позиции до 0 потока памяти перед удалением ZipArchive. Утилизация ZipArchive, я считаю, делает некоторую завершение zip. – Dave

2

Просто вернуть поток ...

private ActionResult CreateZip(IEnumerable files) 
{ 
    if (files.Any()) 
    { 
     MemoryStream zipStream = new MemoryStream(); 
     using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create, false)) 
     { 
      foreach (var f in files) 
      { 
       var entry = archive.CreateEntry(f.FileDownloadName, CompressionLevel.Fastest); 
       using (var entryStream = entry.Open()) 
       { 
        entryStream.Write(f.FileContents, 0, f.FileContents.Length); 
        entryStream.Close(); 
       } 
      } 

     } 

     zipStream.Position = 0; 
     return File(zipStream, MediaTypeNames.Application.Zip, "horta.zip"); 
    } 

    return new EmptyResult(); 
}
+0

yep, делает то же самое ... получает содержимое байта из потока после того, как zipArchive был удален –

0

Попробуйте изменить

using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create, false)) 

в

using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true)) 

При таком использовании, архив вынужден написать в поток, когда он закрыт. Однако, если аргумент конструктора leaveOpen установлен в значение false, он также закроет базовый поток.

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

  • Нет связанных вопросов^_^