69

我正在尝试从一系列字节数组中创建 .NET 4.5 (System.IO.Compression) 中的 Zip 文件。例如,从我正在使用的 API 中,我最终得到 a List<Attachment>,并且每个Attachment都有一个名为 a 的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?
4

3 回答 3

127

经过多一点的玩耍和阅读,我能够弄清楚这一点。以下是如何在不将任何临时数据写入磁盘的情况下创建包含多个文件的 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" };
}
于 2013-06-20T18:14:04.660 回答
6

这是 OP 发布的公认答案的变体。但是,这是针对 WebForms 而不是 MVC。我正在假设 caseAttachmentModel.Body 是一个字节[]

基本上一切都是一样的,只是有一个额外的方法将 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 就已接受答案中的参考资料给出的建议是正确的!

于 2017-05-03T18:49:51.930 回答
2

GZipStream 和 DeflateStream 似乎可以让您使用流/字节数组来解决您的问题,但可能不是大多数用户都可以使用的压缩文件格式。(即,您的文件将具有 .gz 扩展名)如果此文件仅在内部使用,那可能没问题。

我不知道您如何使用 Microsoft 的库制作 ZIP,但我记得这个库支持您可能会发现有用的东西: http: //sevenzipsharp.codeplex.com/

它在 LGPL 下获得许可。

于 2013-06-20T15:10:31.337 回答