从byte[]创建zip文件

70

我想在.NET 4.5(System.IO.Compression)中从一系列字节数组中创建Zip文件。例如,从我使用的API中,我得到一个List<Attachment>,每个Attachment都有一个名为Body的属性,该属性是一个byte[]。 我该如何遍历该列表并创建包含每个附件的zip文件?

目前我认为我必须将每个附件写入磁盘并从那里创建zip文件。

//This is great if I had the files on disk
ZipFile.CreateFromDirectory(startPath, zipPath);
//How can I create it from a series of byte arrays?

你是否查看了System.IO.Compression中的其他类,特别是那些在名称中带有“Stream”的类? - Austin Salonen
http://www.dotnetperls.com/gzipstream http://softdeveloping.blogspot.in/2012/01/example-of-compressing-and.html - Mohit Vashistha
@AustinSalonen - 我可能漏掉了什么,但我认为我不能使用GZipStream输出多个文件。 - Justin Helgerson
3个回答

137

在更多的尝试和阅读后,我成功地解决了这个问题。以下是创建一个包含多个文件的 zip 文件(归档文件)而不需要将任何临时数据写入磁盘的方法:

using (var compressedFileStream = new MemoryStream())
{
    //Create an archive and store the stream in memory.
    using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create, false)) {
        foreach (var caseAttachmentModel in caseAttachmentModels) {
            //Create a zip entry for each attachment
            var zipEntry = zipArchive.CreateEntry(caseAttachmentModel.Name);

            //Get the stream of the attachment
            using (var originalFileStream = new MemoryStream(caseAttachmentModel.Body))
            using (var zipEntryStream = zipEntry.Open()) {
                //Copy the attachment stream to the zip entry stream
                originalFileStream.CopyTo(zipEntryStream);
            }
        }
    }

    return new FileContentResult(compressedFileStream.ToArray(), "application/zip") { FileDownloadName = "Filename.zip" };
}

15
友情提示 - 如果ZipArchive类不可用,请添加对程序集的引用:右键单击“引用”->“添加引用”。在“程序集”下搜索“System.IO”,并勾选“System.IO.Compression.FileSystem”和“System.IO.Compression”。 - Levi Fuller
4
caseAttachmentModels是什么?还有byte[]在哪里? - Demodave
3
我用了这个,但是"compressedFileStream"一直是0长度...有什么想法吗? - Zakaria Sahmane
5
@krillgar你的编辑引入了一个bug。原始代码是在zipArchive关闭之后才有返回语句。通过移除嵌套,现在将返回语句放置在zipArchiveusing语句内部。由于没有处理,归档文件无效。 - Zeph
4
@Zeph 是正确的。我必须添加原始的大括号,并将 return 语句移出一层,以使我的 zipArchive 有效。 - George
显示剩余13条评论

8

这是由发帖者发布的一个广受欢迎的答案的变形。然而,这是针对WebForms而不是MVC的。 我假定caseAttachmentModel.Body是一个byte[]。

基本上一切都相同,只是多了一个将zip作为响应发送的方法。

using (var compressedFileStream = new MemoryStream()) {
    //Create an archive and store the stream in memory.
    using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false))         {
     foreach (var caseAttachmentModel in caseAttachmentModels) {
        //Create a zip entry for each attachment
        var zipEntry = zipArchive.CreateEntry(caseAttachmentModel.Name);

        //Get the stream of the attachment
        using (var originalFileStream = new MemoryStream(caseAttachmentModel.Body)) {
                using (var zipEntryStream = zipEntry.Open()) {
                    //Copy the attachment stream to the zip entry stream
                    originalFileStream.CopyTo(zipEntryStream);
                }
            }
        }
    }
    sendOutZIP(compressedFileStream.ToArray(), "FileName.zip");
}

private void sendOutZIP(byte[] zippedFiles, string filename)
{
    Response.Clear();
    Response.ClearContent();
    Response.ClearHeaders();
    Response.ContentType = "application/x-compressed";
    Response.Charset = string.Empty;
    Response.Cache.SetCacheability(System.Web.HttpCacheability.Public);
    Response.AddHeader("Content-Disposition", "attachment; filename=" + filename);
    Response.BinaryWrite(zippedFiles);
    Response.OutputStream.Flush();
    Response.OutputStream.Close();
    Response.End();
}

我想指出@Levi Fuller在被接受的回答中提到的参考文献建议是非常正确的!

我们可以给zip文件设置密码吗? - Sachin
System.IO.Compression.ZipArchive的文档(https://learn.microsoft.com/en-us/dotnet/api/system.io.compression.ziparchive?view=netframework-4.8)没有显示任何选项来为zip文件设置密码。根据这个(有点老的)线程(https://social.msdn.microsoft.com/Forums/sqlserver/en-US/c2303b11-cf85-41ea-b1a2-caf8b4042bda/systemiocompression-and-passwords?forum=netfxbcl),在.NET中没有密码功能,建议寻找第三方库。 - ShinyCy

2
GZipStream和DeflateStream看起来可以让您使用流/字节数组来解决问题,但也许不能使用大多数用户可用的压缩文件格式。(即,您的文件将具有 .gz扩展名)。如果此文件仅在内部使用,则可能没有关系。我不知道如何使用Microsoft库创建ZIP文件,但我记得这个库支持您可能发现有用的功能:http://sevenzipsharp.codeplex.com/ 它是根据LGPL许可证发布的。

我需要的最终结果是多个文件,我不认为GZipStream支持。 - Justin Helgerson
好的,那么尝试使用SevenZipSharp吧。它是基于7-zip库构建的,但也可以压缩为.zip文件。Codeplex上可能也有类似的库。 - Katana314

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接