Подтвердить что ты не робот

Как я могу разархивировать файл в поток памяти .NET?

У меня есть файлы (от третьих сторон), которые являются FTP'd в каталоге на нашем сервере. Я загружаю их и обрабатываю их даже "х" минут. Отлично работает.

Теперь некоторые файлы являются .zip файлами. Это означает, что я не могу их обработать. Мне нужно сначала распаковать их.

FTP не имеет понятия об zip/unzipping - поэтому мне нужно захватить zip файл, разархивировать его, а затем обработать.

Глядя на MSDN zip api, похоже, что я не могу разархивировать в поток памяти?

Итак, единственный способ сделать это...

  • Разархивируйте файл (в каком каталоге нужно какое-то место для размещения...)
  • Прочитать содержимое файла
  • Удалить файл.

ПРИМЕЧАНИЕ. Содержимое файла невелико - скажем, 4k ↔ 1000k.

4b9b3361

Ответ 1

Поддержка сжатия Zip встроена:

using System.IO;
using System.IO.Compression;
// ^^^ requires a reference to System.IO.Compression.dll
static class Program
{
    const string path = ...
    static void Main()
    {
        using(var file = File.OpenRead(path))
        using(var zip = new ZipArchive(file, ZipArchiveMode.Read))
        {
            foreach(var entry in zip.Entries)
            {
                using(var stream = entry.Open())
                {
                    // do whatever we want with stream
                    // ...
                }
            }
        }
    }
}

Обычно вам следует избегать копирования его в другой поток - просто используйте его "как есть", однако, если вы ему абсолютно необходимы в MemoryStream, вы можете сделать:

using(var ms = new MemoryStream())
{
    stream.CopyTo(ms);
    ms.Position = 0; // rewind
    // do something with ms
}

Ответ 2

Вы можете использовать ZipArchiveEntry.Open, чтобы получить поток.

Этот код предполагает, что zip-архив имеет один текстовый файл.

using (FileStream fs = new FileStream(path, FileMode.Open))
using (ZipArchive zip = new ZipArchive(fs) )
{
    var entry = zip.Entries.First();

    using (StreamReader sr = new StreamReader(entry.Open()))
    {
        Console.WriteLine(sr.ReadToEnd());
    }
}

Ответ 3

Похоже, вот что вам нужно:

   using (var za = ZipFile.OpenRead(path))
   {
       foreach (var entry in sa.Entries)
       {
                using (var r = new StreamReader(entry.Open()))
                {
                    //your code here
                }
       }
   }

Ответ 4

  using (ZipArchive archive = new ZipArchive(webResponse.GetResponseStream()))
      {
      foreach (ZipArchiveEntry entry in archive.Entries)
          {
          Stream s = entry.Open();
          var sr = new StreamReader(s);
          var myStr = sr.ReadToEnd();
          }
      } 

Ответ 5

Вы можете использовать SharpZipLib среди множества других библиотек для достижения этой цели.

Вы можете использовать следующий пример кода, чтобы распаковать в MemoryStream, как показано на их вики:

using ICSharpCode.SharpZipLib.Zip;

// Compresses the supplied memory stream, naming it as zipEntryName, into a zip,
// which is returned as a memory stream or a byte array.
//
public MemoryStream CreateToMemoryStream(MemoryStream memStreamIn, string zipEntryName) {

    MemoryStream outputMemStream = new MemoryStream();
    ZipOutputStream zipStream = new ZipOutputStream(outputMemStream);

    zipStream.SetLevel(3); //0-9, 9 being the highest level of compression

    ZipEntry newEntry = new ZipEntry(zipEntryName);
    newEntry.DateTime = DateTime.Now;

    zipStream.PutNextEntry(newEntry);

    StreamUtils.Copy(memStreamIn, zipStream, new byte[4096]);
    zipStream.CloseEntry();

    zipStream.IsStreamOwner = false;    // False stops the Close also Closing the underlying stream.
    zipStream.Close();          // Must finish the ZipOutputStream before using outputMemStream.

    outputMemStream.Position = 0;
    return outputMemStream;

    // Alternative outputs:
    // ToArray is the cleaner and easiest to use correctly with the penalty of duplicating allocated memory.
    byte[] byteArrayOut = outputMemStream.ToArray();

    // GetBuffer returns a raw buffer raw and so you need to account for the true length yourself.
    byte[] byteArrayOut = outputMemStream.GetBuffer();
    long len = outputMemStream.Length;
}