使用System.IO.Compression在内存中创建ZIP归档文件

本文关键字:创建 ZIP 归档文件 内存 System IO Compression 使用 | 更新日期: 2023-09-27 18:19:16

我正在尝试使用MemoryStream创建一个简单的演示文本文件的ZIP存档,如下所示:

using (var memoryStream = new MemoryStream())
using (var archive = new ZipArchive(memoryStream , ZipArchiveMode.Create))
{
    var demoFile = archive.CreateEntry("foo.txt");
    using (var entryStream = demoFile.Open())
    using (var streamWriter = new StreamWriter(entryStream))
    {
        streamWriter.Write("Bar!");
    }
    using (var fileStream = new FileStream(@"C:'Temp'test.zip", FileMode.Create))
    {
        stream.CopyTo(fileStream);
    }
}

如果我运行这段代码,会创建存档文件本身,但不会创建foo.txt

但是,如果我直接用文件流替换MemoryStream,则可以正确创建存档:

using (var fileStream = new FileStream(@"C:'Temp'test.zip", FileMode.Create))
using (var archive = new ZipArchive(fileStream, FileMode.Create))
{
    // ...
}

是否可以使用MemoryStream来创建没有FileStream的ZIP存档?

使用System.IO.Compression在内存中创建ZIP归档文件

由于ZipArchive创建了无效的ZIP文件,我得到:

using (var memoryStream = new MemoryStream())
{
   using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
   {
      var demoFile = archive.CreateEntry("foo.txt");
      using (var entryStream = demoFile.Open())
      using (var streamWriter = new StreamWriter(entryStream))
      {
         streamWriter.Write("Bar!");
      }
   }
   using (var fileStream = new FileStream(@"C:'Temp'test.zip", FileMode.Create))
   {
      memoryStream.Seek(0, SeekOrigin.Begin);
      memoryStream.CopyTo(fileStream);
   }
}

这表明我们需要在ZipArchive上调用Dispose才能使用它,正如Amir所建议的那样,这可能是因为它将校验和等最终字节写入归档,使其完成。但是为了不关闭流,我们可以在需要将true作为第三个参数传递给ZipArchive后重用它。

只是另一个版本的压缩而不写入任何文件。

string fileName = "export_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".xlsx";
byte[] fileBytes = here is your file in bytes
byte[] compressedBytes;
string fileNameZip = "Export_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".zip";
using (var outStream = new MemoryStream())
{
    using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
    {
        var fileInArchive = archive.CreateEntry(fileName, CompressionLevel.Optimal);
        using (var entryStream = fileInArchive.Open())
        using (var fileToCompressStream = new MemoryStream(fileBytes))
        {
            fileToCompressStream.CopyTo(entryStream);
        }
    }
    compressedBytes = outStream.ToArray();
}

在复制到zip流之前将流的位置设置为0。

using (var memoryStream = new MemoryStream())
{
   using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
   {
         var demoFile = archive.CreateEntry("foo.txt");
         using (var entryStream = demoFile.Open())
         using (var streamWriter = new StreamWriter(entryStream))
         {
             streamWriter.Write("Bar!");
          }
   }
    using (var fileStream = new FileStream(@"C:'Temp'test.zip", FileMode.Create))
    {
         memoryStream.Position=0;
         memoryStream.WriteTo(fileStream);
    }
 }

MVC工作方案

    public ActionResult Index()
    {
        string fileName = "test.pdf";
        string fileName1 = "test.vsix";
        string fileNameZip = "Export_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".zip";
        byte[] fileBytes = System.IO.File.ReadAllBytes(@"C:'test'test.pdf");
        byte[] fileBytes1 = System.IO.File.ReadAllBytes(@"C:'test'test.vsix");
        byte[] compressedBytes;
        using (var outStream = new MemoryStream())
        {
            using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
            {
                var fileInArchive = archive.CreateEntry(fileName, CompressionLevel.Optimal);
                using (var entryStream = fileInArchive.Open())
                using (var fileToCompressStream = new MemoryStream(fileBytes))
                {
                    fileToCompressStream.CopyTo(entryStream);
                }
                var fileInArchive1 = archive.CreateEntry(fileName1, CompressionLevel.Optimal);
                using (var entryStream = fileInArchive1.Open())
                using (var fileToCompressStream = new MemoryStream(fileBytes1))
                {
                    fileToCompressStream.CopyTo(entryStream);
                }

            }
            compressedBytes = outStream.ToArray();
        }
        return File(compressedBytes, "application/zip", fileNameZip);
    }

您需要完成内存流的写入,然后再读取缓冲区

        using (var memoryStream = new MemoryStream())
        {
            using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create))
            {
                var demoFile = archive.CreateEntry("foo.txt");
                using (var entryStream = demoFile.Open())
                using (var streamWriter = new StreamWriter(entryStream))
                {
                    streamWriter.Write("Bar!");
                }
            }
            using (var fileStream = new FileStream(@"C:'Temp'test.zip", FileMode.Create))
            {
                var bytes = memoryStream.GetBuffer();
                fileStream.Write(bytes,0,bytes.Length );
            }
        }
using System;
using System.IO;
using System.IO.Compression;
namespace ConsoleApplication
{
    class Program`enter code here`
    {
        static void Main(string[] args)
        {
            using (FileStream zipToOpen = new FileStream(@"c:'users'exampleuser'release.zip", FileMode.Open))
            {
                using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
                {
                    ZipArchiveEntry readmeEntry = archive.CreateEntry("Readme.txt");
                    using (StreamWriter writer = new StreamWriter(readmeEntry.Open()))
                    {
                            writer.WriteLine("Information about this package.");
                            writer.WriteLine("========================");
                    }
                }
            }
        }
    }
}

返回包含zip文件的流

public static Stream ZipGenerator(List<string> files)
    {
        ZipArchiveEntry fileInArchive;
        Stream entryStream;
        int i = 0;
        List<byte[]> byteArray = new List<byte[]>();
        foreach (var file in files)
        {
            byteArray.Add(File.ReadAllBytes(file));
        }
        var outStream = new MemoryStream();
        using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
        {
            foreach (var file in files)
            {
                fileInArchive=(archive.CreateEntry(Path.GetFileName(file), CompressionLevel.Optimal));
                using (entryStream = fileInArchive.Open())
                {
                        using (var fileToCompressStream = new MemoryStream(byteArray[i]))
                        {
                            fileToCompressStream.CopyTo(entryStream);
                        }
                        i++;
                }
            }
        }
        outStream.Position = 0;
        return outStream;
    }

如果你想写zip到文件流

using (var fileStream = new FileStream(@"D:'Tools'DBExtractor'DBExtractor'bin'Debug'test.zip", FileMode.Create))
{
   outStream.Position = 0;
   outStream.WriteTo(fileStream);
}

"

我迟到了,但是在某些情况下,您无法访问ZipArchive的构造函数来设置leaveOpen参数,并且您不希望将ZIP写入磁盘。在我的情况下,我在内部使用的AsiceArchive类创建了一个ZipArchive,但没有将leaveOpen设置为true。

我创建了一个Stream的子类,它将所有调用委托给内部流(使用ReSharper单击几下)。这个类不是可丢弃的,所以当ZipArchive被丢弃时,内部流不会发生任何变化。

public class NondisposingStreamWrapper : Stream
{
    private readonly Stream _streamImplementation;
    public NondisposingStreamWrapper(Stream inner) => _streamImplementation = inner;
    public override void Flush() => _streamImplementation.Flush();
    public override int Read(byte[] buffer, int offset, int count) => _streamImplementation.Read(buffer, offset, count);
    public override long Seek(long offset, SeekOrigin origin) => _streamImplementation.Seek(offset, origin);
    public override void SetLength(long value) => _streamImplementation.SetLength(value);
    public override void Write(byte[] buffer, int offset, int count) => _streamImplementation.Write(buffer, offset, count);
    public override bool CanRead => _streamImplementation.CanRead;
    public override bool CanSeek => _streamImplementation.CanSeek;
    public override bool CanWrite => _streamImplementation.CanWrite;
    public override long Length => _streamImplementation.Length;
    public override long Position
    {
        get => _streamImplementation.Position;
        set => _streamImplementation.Position = value;
    }
}

像这样使用:

using var memoryStream = new MemoryStream();
var output = new NondisposingStreamWrapper(memoryStream);
using (var archive = new ZipArchive(output, ZipArchiveMode.Create))
{
    // add entries to archive
}
memoryStream.Flush();
memoryStream.Position = 0;
// write to file just for testing purposes
File.WriteAllBytes("out.zip", memoryStream.ToArray());

这是将实体转换为XML文件然后压缩它的方法:

private  void downloadFile(EntityXML xml) {
string nameDownloadXml = "File_1.xml";
string nameDownloadZip = "File_1.zip";
var serializer = new XmlSerializer(typeof(EntityXML));
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.AddHeader("content-disposition", "attachment;filename=" + nameDownloadZip);
using (var memoryStream = new MemoryStream())
{
    using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
    {
        var demoFile = archive.CreateEntry(nameDownloadXml);
        using (var entryStream = demoFile.Open())
        using (StreamWriter writer = new StreamWriter(entryStream, System.Text.Encoding.UTF8))
        {
            serializer.Serialize(writer, xml);
        }
    }
    using (var fileStream = Response.OutputStream)
    {
        memoryStream.Seek(0, SeekOrigin.Begin);
        memoryStream.CopyTo(fileStream);
    }
}
Response.End();

}

以防万一,如果有人想通过SaveFileDialog保存动态zip文件。

        var logFileName = "zip_filename.zip";
        appLogSaver.FileName = logFileName;
        appLogSaver.Filter = "LogFiles|*.zip";
        appLogSaver.DefaultExt = "zip";
        DialogResult resDialog = appLogSaver.ShowDialog();
        if (resDialog.ToString() == "OK")
        {
            System.IO.FileStream fs = (System.IO.FileStream)appLogSaver.OpenFile();
            using (var memoryStream = new MemoryStream())
            {
                using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
                {
                    var demoFile = archive.CreateEntry("foo.txt");
                    using (var entryStream = demoFile.Open())
                    {
                        using (var streamWriter = new StreamWriter(entryStream))
                        {
                            //read your existing file and put the content here 
                            streamWriter.Write("Bar!");
                        }
                    }
                    var demoFile2 = archive.CreateEntry("foo2.txt");
                    using (var entryStream = demoFile2.Open())
                    {
                        using (var streamWriter = new StreamWriter(entryStream))
                        {
                            streamWriter.Write("Bar2!");
                        }
                    }
                }
                memoryStream.Seek(0, SeekOrigin.Begin);
                memoryStream.CopyTo(fs);
            }
            fs.Close();
        }

对我来说,这样的东西是可以的:

using (var memoryStream = new MemoryStream())
{
   using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
   {
      var file = archive.CreateEntry("file.json");
      using var entryStream = file.Open();
      using var streamWriter = new StreamWriter(entryStream);
      streamWriter.WriteLine(someJsonLine);
   }
}
       private void button6_Click(object sender, EventArgs e)
    {
        //create With Input FileNames
        AddFileToArchive_InputByte(new ZipItem[]{ new ZipItem( @"E:'b'1.jpg",@"images'1.jpg"),
            new ZipItem(@"E:'b'2.txt",@"text'2.txt")}, @"C:'test.zip");
        //create with input stream
        AddFileToArchive_InputByte(new ZipItem[]{ new ZipItem(File.ReadAllBytes( @"E:'b'1.jpg"),@"images'1.jpg"),
            new ZipItem(File.ReadAllBytes(@"E:'b'2.txt"),@"text'2.txt")}, @"C:'test.zip");
        //Create Archive And Return StreamZipFile
        MemoryStream GetStreamZipFile = AddFileToArchive(new ZipItem[]{ new ZipItem( @"E:'b'1.jpg",@"images'1.jpg"),
            new ZipItem(@"E:'b'2.txt",@"text'2.txt")});

        //Extract in memory
        ZipItem[] ListitemsWithBytes = ExtractItems(@"C:'test.zip");
        //Choese Files For Extract To memory
        List<string> ListFileNameForExtract = new List<string>(new string[] { @"images'1.jpg", @"text'2.txt" });
        ListitemsWithBytes = ExtractItems(@"C:'test.zip", ListFileNameForExtract);

        // Choese Files For Extract To Directory
        ExtractItems(@"C:'test.zip", ListFileNameForExtract, "c:''extractFiles");
    }
    public struct ZipItem
    {
        string _FileNameSource;
        string _PathinArchive;
        byte[] _Bytes;
        public ZipItem(string __FileNameSource, string __PathinArchive)
        {
            _Bytes=null ;
            _FileNameSource = __FileNameSource;
            _PathinArchive = __PathinArchive;
        }
        public ZipItem(byte[] __Bytes, string __PathinArchive)
        {
            _Bytes = __Bytes;
            _FileNameSource = "";
            _PathinArchive = __PathinArchive;
        }
        public string FileNameSource
        {
            set
            {
                FileNameSource = value;
            }
            get
            {
                return _FileNameSource;
            }
        }
        public string PathinArchive
        {
            set
            {
                _PathinArchive = value;
            }
            get
            {
                return _PathinArchive;
            }
        }
        public byte[] Bytes
        {
            set
            {
                _Bytes = value;
            }
            get
            {
                return _Bytes;
            }
        }
    }

     public void AddFileToArchive(ZipItem[] ZipItems, string SeveToFile)
    {
        MemoryStream memoryStream = new MemoryStream();
        //Create Empty Archive
        ZipArchive archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true);
        foreach (ZipItem item in ZipItems)
        {
            //Create Path File in Archive
            ZipArchiveEntry FileInArchive = archive.CreateEntry(item.PathinArchive);

            //Open File in Archive For Write
            var OpenFileInArchive = FileInArchive.Open();
            //Read Stream
            FileStream fsReader = new FileStream(item.FileNameSource, FileMode.Open, FileAccess.Read);
            byte[] ReadAllbytes = new byte[4096];//Capcity buffer
            int ReadByte = 0;
            while (fsReader.Position != fsReader.Length)
            {
                //Read Bytes
                ReadByte = fsReader.Read(ReadAllbytes, 0, ReadAllbytes.Length);
                //Write Bytes
                OpenFileInArchive.Write(ReadAllbytes, 0, ReadByte);
            }
            fsReader.Dispose();
            OpenFileInArchive.Close();

        }
        archive.Dispose();
        using (var fileStream = new FileStream(SeveToFile, FileMode.Create))
        {
            memoryStream.Seek(0, SeekOrigin.Begin);
            memoryStream.CopyTo(fileStream);
        }


    }
     public MemoryStream  AddFileToArchive(ZipItem[] ZipItems)
    {
        MemoryStream memoryStream = new MemoryStream();
        //Create Empty Archive
        ZipArchive archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true);
        foreach (ZipItem item in ZipItems)
        {
            //Create Path File in Archive
            ZipArchiveEntry FileInArchive = archive.CreateEntry(item.PathinArchive);

            //Open File in Archive For Write
            var OpenFileInArchive = FileInArchive.Open();
            //Read Stream
            FileStream fsReader = new FileStream(item.FileNameSource, FileMode.Open, FileAccess.Read);
            byte[] ReadAllbytes = new byte[4096];//Capcity buffer
            int ReadByte = 0;
            while (fsReader.Position != fsReader.Length)
            {
                //Read Bytes
                ReadByte = fsReader.Read(ReadAllbytes, 0, ReadAllbytes.Length);
                //Write Bytes
                OpenFileInArchive.Write(ReadAllbytes, 0, ReadByte);
            }
            fsReader.Dispose();
            OpenFileInArchive.Close();

        }
        archive.Dispose();


        return memoryStream;

    }
     public void AddFileToArchive_InputByte(ZipItem[] ZipItems, string SeveToFile)
    {
        MemoryStream memoryStream = new MemoryStream();
        //Create Empty Archive
        ZipArchive archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true);
        foreach (ZipItem item in ZipItems)
        {
            //Create Path File in Archive
            ZipArchiveEntry FileInArchive = archive.CreateEntry(item.PathinArchive);

            //Open File in Archive For Write
            var OpenFileInArchive = FileInArchive.Open();
            //Read Stream
          //  FileStream fsReader = new FileStream(item.FileNameSource, FileMode.Open, FileAccess.Read);
            byte[] ReadAllbytes = new byte[4096];//Capcity buffer
            int ReadByte = 4096 ;int  TotalWrite=0;
            while (TotalWrite != item.Bytes.Length)
            {
                if(TotalWrite+4096>item.Bytes.Length)
                 ReadByte=item.Bytes.Length-TotalWrite;

                Array.Copy(item.Bytes, TotalWrite, ReadAllbytes, 0, ReadByte);


                //Write Bytes
                OpenFileInArchive.Write(ReadAllbytes, 0, ReadByte);
                TotalWrite += ReadByte;
            }
            OpenFileInArchive.Close();

        }
        archive.Dispose();
        using (var fileStream = new FileStream(SeveToFile, FileMode.Create))
        {
            memoryStream.Seek(0, SeekOrigin.Begin);
            memoryStream.CopyTo(fileStream);
        }

    }
     public MemoryStream  AddFileToArchive_InputByte(ZipItem[] ZipItems)
    {
        MemoryStream memoryStream = new MemoryStream();
        //Create Empty Archive
        ZipArchive archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true);
        foreach (ZipItem item in ZipItems)
        {
            //Create Path File in Archive
            ZipArchiveEntry FileInArchive = archive.CreateEntry(item.PathinArchive);

            //Open File in Archive For Write
            var OpenFileInArchive = FileInArchive.Open();
            //Read Stream
          //  FileStream fsReader = new FileStream(item.FileNameSource, FileMode.Open, FileAccess.Read);
            byte[] ReadAllbytes = new byte[4096];//Capcity buffer
            int ReadByte = 4096 ;int  TotalWrite=0;
            while (TotalWrite != item.Bytes.Length)
            {
                if(TotalWrite+4096>item.Bytes.Length)
                 ReadByte=item.Bytes.Length-TotalWrite;

                Array.Copy(item.Bytes, TotalWrite, ReadAllbytes, 0, ReadByte);


                //Write Bytes
                OpenFileInArchive.Write(ReadAllbytes, 0, ReadByte);
                TotalWrite += ReadByte;
            }
            OpenFileInArchive.Close();

        }
        archive.Dispose();

        return memoryStream;
    }
     public void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName)
     {
         //Opens the zip file up to be read
         using (ZipArchive archive = ZipFile.OpenRead(sourceArchiveFileName))
         {
             if (Directory.Exists(destinationDirectoryName)==false )
                 Directory.CreateDirectory(destinationDirectoryName);
             //Loops through each file in the zip file
             archive.ExtractToDirectory(destinationDirectoryName);
         }
     }  
     public void   ExtractItems(string sourceArchiveFileName,List< string> _PathFilesinArchive, string destinationDirectoryName)
     {
         //Opens the zip file up to be read
         using (ZipArchive archive = ZipFile.OpenRead(sourceArchiveFileName))
         {

             //Loops through each file in the zip file
             foreach (ZipArchiveEntry file in archive.Entries)
             {
                 int PosResult = _PathFilesinArchive.IndexOf(file.FullName);
                 if (PosResult != -1)
                 {
                     //Create Folder
                     if (Directory.Exists( destinationDirectoryName + "''" +Path.GetDirectoryName( _PathFilesinArchive[PosResult])) == false)
                         Directory.CreateDirectory(destinationDirectoryName + "''" + Path.GetDirectoryName(_PathFilesinArchive[PosResult]));
                     Stream OpenFileGetBytes = file.Open();
                     FileStream   FileStreamOutput = new FileStream(destinationDirectoryName + "''" + _PathFilesinArchive[PosResult], FileMode.Create);
                     byte[] ReadAllbytes = new byte[4096];//Capcity buffer
                     int ReadByte = 0; int TotalRead = 0; 
                     while (TotalRead != file.Length)
                     {
                         //Read Bytes
                         ReadByte = OpenFileGetBytes.Read(ReadAllbytes, 0, ReadAllbytes.Length);
                         TotalRead += ReadByte;
                         //Write Bytes
                         FileStreamOutput.Write(ReadAllbytes, 0, ReadByte);
                     }
                     FileStreamOutput.Close();
                     OpenFileGetBytes.Close();

                     _PathFilesinArchive.RemoveAt(PosResult);
                 }
                 if (_PathFilesinArchive.Count == 0)
                     break;
             }
         }

     }
     public ZipItem[] ExtractItems(string sourceArchiveFileName)
     {
       List<  ZipItem> ZipItemsReading = new List<ZipItem>();
         //Opens the zip file up to be read
         using (ZipArchive archive = ZipFile.OpenRead(sourceArchiveFileName))
         {

             //Loops through each file in the zip file
             foreach (ZipArchiveEntry file in archive.Entries)
             {
                 Stream OpenFileGetBytes = file.Open();
                 MemoryStream memstreams = new MemoryStream();
                 byte[] ReadAllbytes = new byte[4096];//Capcity buffer
                 int ReadByte = 0; int TotalRead = 0;
                 while (TotalRead != file.Length)
                 {
                     //Read Bytes
                     ReadByte = OpenFileGetBytes.Read(ReadAllbytes, 0, ReadAllbytes.Length);
                     TotalRead += ReadByte;
                     //Write Bytes
                     memstreams.Write(ReadAllbytes, 0, ReadByte);
                 }
                 memstreams.Position = 0;
                 OpenFileGetBytes.Close();
                 memstreams.Dispose();
                 ZipItemsReading.Add(new ZipItem(memstreams.ToArray(),file.FullName));

             }
         }
         return ZipItemsReading.ToArray();
     }
     public ZipItem[] ExtractItems(string sourceArchiveFileName,List< string> _PathFilesinArchive)
     {
       List<  ZipItem> ZipItemsReading = new List<ZipItem>();
         //Opens the zip file up to be read
         using (ZipArchive archive = ZipFile.OpenRead(sourceArchiveFileName))
         {
             //Loops through each file in the zip file
             foreach (ZipArchiveEntry file in archive.Entries)
             {
                 int PosResult = _PathFilesinArchive.IndexOf(file.FullName); 
                 if (PosResult!= -1)
                 {
                     Stream OpenFileGetBytes = file.Open();
                     MemoryStream memstreams = new MemoryStream();
                     byte[] ReadAllbytes = new byte[4096];//Capcity buffer
                     int ReadByte = 0; int TotalRead = 0;  
                     while (TotalRead != file.Length)
                     {
                         //Read Bytes
                         ReadByte = OpenFileGetBytes.Read(ReadAllbytes, 0, ReadAllbytes.Length);
                         TotalRead += ReadByte;
                         //Write Bytes
                         memstreams.Write(ReadAllbytes, 0, ReadByte);
                     }
                     //Create item
                     ZipItemsReading.Add(new ZipItem(memstreams.ToArray(),file.FullName));
                     OpenFileGetBytes.Close();
                     memstreams.Dispose();

                     _PathFilesinArchive.RemoveAt(PosResult);
                 }
                 if (_PathFilesinArchive.Count == 0)
                     break;

             }
         }
         return ZipItemsReading.ToArray();
     }